Add support for VarAnd between integers.
[wine/multimedia.git] / dlls / oleaut32 / variant.c
blobd1d766804f8703b6209f69949238fe06af6771ae
1 /*
2 * VARIANT
4 * Copyright 1998 Jean-Claude Cote
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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.
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.
37 #include "config.h"
39 #include <string.h>
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <math.h>
43 #include <time.h>
45 #ifdef HAVE_FLOAT_H
46 # include <float.h>
47 #endif
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 #include "typelib.h"
57 WINE_DEFAULT_DEBUG_CHANNEL(ole);
59 #define SYSDUPSTRING(str) SysAllocStringLen((str), SysStringLen(str))
61 #ifndef FLT_MAX
62 # ifdef MAXFLOAT
63 # define FLT_MAX MAXFLOAT
64 # else
65 # error "Can't find #define for MAXFLOAT/FLT_MAX"
66 # endif
67 #endif
69 #undef CHAR_MAX
70 #undef CHAR_MIN
71 static const char CHAR_MAX = 127;
72 static const char CHAR_MIN = -128;
73 static const BYTE UI1_MAX = 255;
74 static const BYTE UI1_MIN = 0;
75 static const unsigned short UI2_MAX = 65535;
76 static const unsigned short UI2_MIN = 0;
77 static const short I2_MAX = 32767;
78 static const short I2_MIN = -32768;
79 static const unsigned long UI4_MAX = 4294967295U;
80 static const unsigned long UI4_MIN = 0;
81 static const long I4_MAX = 2147483647;
82 static const long I4_MIN = -(2147483648U);
83 static const DATE DATE_MIN = -657434;
84 static const DATE DATE_MAX = 2958465;
87 /* This mask is used to set a flag in wReserved1 of
88 * the VARIANTARG structure. The flag indicates if
89 * the API function is using an inner variant or not.
91 #define PROCESSING_INNER_VARIANT 0x0001
93 /* General use buffer.
95 #define BUFFER_MAX 1024
96 static char pBuffer[BUFFER_MAX];
99 * Note a leap year is one that is a multiple of 4
100 * but not of a 100. Except if it is a multiple of
101 * 400 then it is a leap year.
105 * Use 365 days/year and a manual calculation for leap year days
106 * to keep arithmetic simple
108 static const double DAYS_IN_ONE_YEAR = 365.0;
111 * Token definitions for Varient Formatting
112 * Worked out by experimentation on a w2k machine. Doesnt appear to be
113 * documented anywhere obviously so keeping definitions internally
116 /* Pre defined tokens */
117 #define TOK_COPY 0x00
118 #define TOK_END 0x02
119 #define LARGEST_TOKENID 6
121 /* Mapping of token name to id put into the tokenized form
122 Note testing on W2K shows aaaa and oooo are not parsed??!! */
123 #define TOK_COLON 0x03
124 #define TOK_SLASH 0x04
125 #define TOK_c 0x05
126 #define TOK_d 0x08
127 #define TOK_dd 0x09
128 #define TOK_ddd 0x0a
129 #define TOK_dddd 0x0b
130 #define TOK_ddddd 0x0c
131 #define TOK_dddddd 0x0d
132 #define TOK_w 0x0f
133 #define TOK_ww 0x10
134 #define TOK_m 0x11
135 #define TOK_mm 0x12
136 #define TOK_mmm 0x13
137 #define TOK_mmmm 0x14
138 #define TOK_q 0x06
139 #define TOK_y 0x15
140 #define TOK_yy 0x16
141 #define TOK_yyyy 0x18
142 #define TOK_h 0x1e
143 #define TOK_Hh 0x1f
144 #define TOK_N 0x1a
145 #define TOK_Nn 0x1b
146 #define TOK_S 0x1c
147 #define TOK_Ss 0x1d
148 #define TOK_ttttt 0x07
149 #define TOK_AMsPM 0x2f
150 #define TOK_amspm 0x32
151 #define TOK_AsP 0x30
152 #define TOK_asp 0x33
153 #define TOK_AMPM 0x2e
155 typedef struct tagFORMATTOKEN {
156 char *str;
157 BYTE tokenSize;
158 BYTE tokenId;
159 int varTypeRequired;
160 } FORMATTOKEN;
162 typedef struct tagFORMATHDR {
163 BYTE len;
164 BYTE hex3;
165 BYTE hex6;
166 BYTE reserved[8];
167 } FORMATHDR;
169 FORMATTOKEN formatTokens[] = { /* FIXME: Only date formats so far */
170 {":" , 1, TOK_COLON , 0},
171 {"/" , 1, TOK_SLASH , 0},
172 {"c" , 1, TOK_c , VT_DATE},
173 {"dddddd", 6, TOK_dddddd , VT_DATE},
174 {"ddddd" , 5, TOK_ddddd , VT_DATE},
175 {"dddd" , 4, TOK_dddd , VT_DATE},
176 {"ddd" , 3, TOK_ddd , VT_DATE},
177 {"dd" , 2, TOK_dd , VT_DATE},
178 {"d" , 1, TOK_d , VT_DATE},
179 {"ww" , 2, TOK_ww , VT_DATE},
180 {"w" , 1, TOK_w , VT_DATE},
181 {"mmmm" , 4, TOK_mmmm , VT_DATE},
182 {"mmm" , 3, TOK_mmm , VT_DATE},
183 {"mm" , 2, TOK_mm , VT_DATE},
184 {"m" , 1, TOK_m , VT_DATE},
185 {"q" , 1, TOK_q , VT_DATE},
186 {"yyyy" , 4, TOK_yyyy , VT_DATE},
187 {"yy" , 2, TOK_yy , VT_DATE},
188 {"y" , 1, TOK_y , VT_DATE},
189 {"h" , 1, TOK_h , VT_DATE},
190 {"Hh" , 2, TOK_Hh , VT_DATE},
191 {"Nn" , 2, TOK_Nn , VT_DATE},
192 {"N" , 1, TOK_N , VT_DATE},
193 {"S" , 1, TOK_S , VT_DATE},
194 {"Ss" , 2, TOK_Ss , VT_DATE},
195 {"ttttt" , 5, TOK_ttttt , VT_DATE},
196 {"AM/PM" , 5, TOK_AMsPM , VT_DATE},
197 {"am/pm" , 5, TOK_amspm , VT_DATE},
198 {"A/P" , 3, TOK_AsP , VT_DATE},
199 {"a/p" , 3, TOK_asp , VT_DATE},
200 {"AMPM" , 4, TOK_AMPM , VT_DATE},
201 {0x00 , 0, 0 , VT_NULL}
204 /******************************************************************************
205 * DateTimeStringToTm [INTERNAL]
207 * Converts a string representation of a date and/or time to a tm structure.
209 * Note this function uses the postgresql date parsing functions found
210 * in the parsedt.c file.
212 * Returns TRUE if successful.
214 * Note: This function does not parse the day of the week,
215 * daylight savings time. It will only fill the followin fields in
216 * the tm struct, tm_sec, tm_min, tm_hour, tm_year, tm_day, tm_mon.
218 ******************************************************************************/
219 static BOOL DateTimeStringToTm( OLECHAR* strIn, DWORD dwFlags, struct tm* pTm )
221 BOOL res = FALSE;
222 double fsec;
223 int tzp;
224 int dtype;
225 int nf;
226 char *field[MAXDATEFIELDS];
227 int ftype[MAXDATEFIELDS];
228 char lowstr[MAXDATELEN + 1];
229 char* strDateTime = NULL;
231 /* Convert the string to ASCII since this is the only format
232 * postgesql can handle.
234 strDateTime = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
236 if( strDateTime != NULL )
238 /* Make sure we don't go over the maximum length
239 * accepted by postgesql.
241 if( strlen( strDateTime ) <= MAXDATELEN )
243 if( ParseDateTime( strDateTime, lowstr, field, ftype, MAXDATEFIELDS, &nf) == 0 )
245 if( dwFlags & VAR_DATEVALUEONLY )
247 /* Get the date information.
248 * It returns 0 if date information was
249 * present and 1 if only time information was present.
250 * -1 if an error occures.
252 if( DecodeDateTime(field, ftype, nf, &dtype, pTm, &fsec, &tzp) == 0 )
254 /* Eliminate the time information since we
255 * were asked to get date information only.
257 pTm->tm_sec = 0;
258 pTm->tm_min = 0;
259 pTm->tm_hour = 0;
260 res = TRUE;
263 if( dwFlags & VAR_TIMEVALUEONLY )
265 /* Get time information only.
267 if( DecodeTimeOnly(field, ftype, nf, &dtype, pTm, &fsec) == 0 )
269 res = TRUE;
272 else
274 /* Get both date and time information.
275 * It returns 0 if date information was
276 * present and 1 if only time information was present.
277 * -1 if an error occures.
279 if( DecodeDateTime(field, ftype, nf, &dtype, pTm, &fsec, &tzp) != -1 )
281 res = TRUE;
286 HeapFree( GetProcessHeap(), 0, strDateTime );
289 return res;
297 /******************************************************************************
298 * TmToDATE [INTERNAL]
300 * The date is implemented using an 8 byte floating-point number.
301 * Days are represented by whole numbers increments starting with 0.00 has
302 * being December 30 1899, midnight.
303 * The hours are expressed as the fractional part of the number.
304 * December 30 1899 at midnight = 0.00
305 * January 1 1900 at midnight = 2.00
306 * January 4 1900 at 6 AM = 5.25
307 * January 4 1900 at noon = 5.50
308 * December 29 1899 at midnight = -1.00
309 * December 18 1899 at midnight = -12.00
310 * December 18 1899 at 6AM = -12.25
311 * December 18 1899 at 6PM = -12.75
312 * December 19 1899 at midnight = -11.00
313 * The tm structure is as follows:
314 * struct tm {
315 * int tm_sec; seconds after the minute - [0,59]
316 * int tm_min; minutes after the hour - [0,59]
317 * int tm_hour; hours since midnight - [0,23]
318 * int tm_mday; day of the month - [1,31]
319 * int tm_mon; months since January - [0,11]
320 * int tm_year; years
321 * int tm_wday; days since Sunday - [0,6]
322 * int tm_yday; days since January 1 - [0,365]
323 * int tm_isdst; daylight savings time flag
324 * };
326 * Note: This function does not use the tm_wday, tm_yday, tm_wday,
327 * and tm_isdst fields of the tm structure. And only converts years
328 * after 1900.
330 * Returns TRUE if successful.
332 static BOOL TmToDATE( struct tm* pTm, DATE *pDateOut )
334 int leapYear = 0;
336 /* Hmmm... An uninitialized Date in VB is December 30 1899 so
337 Start at 0. This is the way DATE is defined. */
339 /* Start at 1. This is the way DATE is defined.
340 * January 1, 1900 at Midnight is 1.00.
341 * January 1, 1900 at 6AM is 1.25.
342 * and so on.
344 *pDateOut = 1;
346 if( (pTm->tm_year - 1900) >= 0 ) {
348 /* Add the number of days corresponding to
349 * tm_year.
351 *pDateOut += (pTm->tm_year - 1900) * 365;
353 /* Add the leap days in the previous years between now and 1900.
354 * Note a leap year is one that is a multiple of 4
355 * but not of a 100. Except if it is a multiple of
356 * 400 then it is a leap year.
357 * Copied + reversed functionality into TmToDate
359 *pDateOut += ( (pTm->tm_year - 1) / 4 ) - ( 1900 / 4 );
360 *pDateOut -= ( (pTm->tm_year - 1) / 100 ) - ( 1900 / 100 );
361 *pDateOut += ( (pTm->tm_year - 1) / 400 ) - ( 1900 / 400 );
363 /* Set the leap year flag if the
364 * current year specified by tm_year is a
365 * leap year. This will be used to add a day
366 * to the day count.
368 if( isleap( pTm->tm_year ) )
369 leapYear = 1;
371 /* Add the number of days corresponding to
372 * the month. (remember tm_mon is 0..11)
374 switch( pTm->tm_mon )
376 case 1:
377 *pDateOut += 31;
378 break;
379 case 2:
380 *pDateOut += ( 59 + leapYear );
381 break;
382 case 3:
383 *pDateOut += ( 90 + leapYear );
384 break;
385 case 4:
386 *pDateOut += ( 120 + leapYear );
387 break;
388 case 5:
389 *pDateOut += ( 151 + leapYear );
390 break;
391 case 6:
392 *pDateOut += ( 181 + leapYear );
393 break;
394 case 7:
395 *pDateOut += ( 212 + leapYear );
396 break;
397 case 8:
398 *pDateOut += ( 243 + leapYear );
399 break;
400 case 9:
401 *pDateOut += ( 273 + leapYear );
402 break;
403 case 10:
404 *pDateOut += ( 304 + leapYear );
405 break;
406 case 11:
407 *pDateOut += ( 334 + leapYear );
408 break;
410 /* Add the number of days in this month.
412 *pDateOut += pTm->tm_mday;
414 /* Add the number of seconds, minutes, and hours
415 * to the DATE. Note these are the fracionnal part
416 * of the DATE so seconds / number of seconds in a day.
418 } else {
419 *pDateOut = 0;
422 *pDateOut += pTm->tm_hour / 24.0;
423 *pDateOut += pTm->tm_min / 1440.0;
424 *pDateOut += pTm->tm_sec / 86400.0;
425 return TRUE;
428 /******************************************************************************
429 * DateToTm [INTERNAL]
431 * This function converts a windows DATE to a tm structure.
433 * It does not fill all the fields of the tm structure.
434 * Here is a list of the fields that are filled:
435 * tm_sec, tm_min, tm_hour, tm_year, tm_day, tm_mon.
437 * Note this function does not support dates before the January 1, 1900
438 * or ( dateIn < 2.0 ).
440 * Returns TRUE if successful.
442 BOOL DateToTm( DATE dateIn, DWORD dwFlags, struct tm* pTm )
444 double decimalPart = 0.0;
445 double wholePart = 0.0;
447 memset(pTm,0,sizeof(*pTm));
449 /* Because of the nature of DATE format which
450 * associates 2.0 to January 1, 1900. We will
451 * remove 1.0 from the whole part of the DATE
452 * so that in the following code 1.0
453 * will correspond to January 1, 1900.
454 * This simplifies the processing of the DATE value.
456 decimalPart = fmod( dateIn, 1.0 ); /* Do this before the -1, otherwise 0.xx goes negative */
457 dateIn -= 1.0;
458 wholePart = (double) floor( dateIn );
460 if( !(dwFlags & VAR_TIMEVALUEONLY) )
462 unsigned int nDay = 0;
463 int leapYear = 0;
464 double yearsSince1900 = 0;
466 /* Hard code dates smaller than January 1, 1900. */
467 if( dateIn < 2.0 ) {
468 pTm->tm_year = 1899;
469 pTm->tm_mon = 11; /* December as tm_mon is 0..11 */
470 if( dateIn < 1.0 ) {
471 pTm->tm_mday = 30;
472 dateIn = dateIn * -1.0; /* Ensure +ve for time calculation */
473 decimalPart = decimalPart * -1.0; /* Ensure +ve for time calculation */
474 } else {
475 pTm->tm_mday = 31;
478 } else {
480 /* Start at 1900, this is where the DATE time 0.0 starts.
482 pTm->tm_year = 1900;
483 /* find in what year the day in the "wholePart" falls into.
484 * add the value to the year field.
486 yearsSince1900 = floor( (wholePart / DAYS_IN_ONE_YEAR) + 0.001 );
487 pTm->tm_year += yearsSince1900;
488 /* determine if this is a leap year.
490 if( isleap( pTm->tm_year ) )
492 leapYear = 1;
493 wholePart++;
496 /* find what day of that year the "wholePart" corresponds to.
497 * Note: nDay is in [1-366] format
499 nDay = (((unsigned int) wholePart) - ((pTm->tm_year-1900) * DAYS_IN_ONE_YEAR ));
501 /* Remove the leap days in the previous years between now and 1900.
502 * Note a leap year is one that is a multiple of 4
503 * but not of a 100. Except if it is a multiple of
504 * 400 then it is a leap year.
505 * Copied + reversed functionality from TmToDate
507 nDay -= ( (pTm->tm_year - 1) / 4 ) - ( 1900 / 4 );
508 nDay += ( (pTm->tm_year - 1) / 100 ) - ( 1900 / 100 );
509 nDay -= ( (pTm->tm_year - 1) / 400 ) - ( 1900 / 400 );
511 /* Set the tm_yday value.
512 * Note: The day must be converted from [1-366] to [0-365]
514 /*pTm->tm_yday = nDay - 1;*/
515 /* find which month this day corresponds to.
517 if( nDay <= 31 )
519 pTm->tm_mday = nDay;
520 pTm->tm_mon = 0;
522 else if( nDay <= ( 59 + leapYear ) )
524 pTm->tm_mday = nDay - 31;
525 pTm->tm_mon = 1;
527 else if( nDay <= ( 90 + leapYear ) )
529 pTm->tm_mday = nDay - ( 59 + leapYear );
530 pTm->tm_mon = 2;
532 else if( nDay <= ( 120 + leapYear ) )
534 pTm->tm_mday = nDay - ( 90 + leapYear );
535 pTm->tm_mon = 3;
537 else if( nDay <= ( 151 + leapYear ) )
539 pTm->tm_mday = nDay - ( 120 + leapYear );
540 pTm->tm_mon = 4;
542 else if( nDay <= ( 181 + leapYear ) )
544 pTm->tm_mday = nDay - ( 151 + leapYear );
545 pTm->tm_mon = 5;
547 else if( nDay <= ( 212 + leapYear ) )
549 pTm->tm_mday = nDay - ( 181 + leapYear );
550 pTm->tm_mon = 6;
552 else if( nDay <= ( 243 + leapYear ) )
554 pTm->tm_mday = nDay - ( 212 + leapYear );
555 pTm->tm_mon = 7;
557 else if( nDay <= ( 273 + leapYear ) )
559 pTm->tm_mday = nDay - ( 243 + leapYear );
560 pTm->tm_mon = 8;
562 else if( nDay <= ( 304 + leapYear ) )
564 pTm->tm_mday = nDay - ( 273 + leapYear );
565 pTm->tm_mon = 9;
567 else if( nDay <= ( 334 + leapYear ) )
569 pTm->tm_mday = nDay - ( 304 + leapYear );
570 pTm->tm_mon = 10;
572 else if( nDay <= ( 365 + leapYear ) )
574 pTm->tm_mday = nDay - ( 334 + leapYear );
575 pTm->tm_mon = 11;
579 if( !(dwFlags & VAR_DATEVALUEONLY) )
581 /* find the number of seconds in this day.
582 * fractional part times, hours, minutes, seconds.
583 * Note: 0.1 is hack to ensure figures come out in whole numbers
584 * due to floating point inaccuracies
586 pTm->tm_hour = (int) ( decimalPart * 24 );
587 pTm->tm_min = (int) ( ( ( decimalPart * 24 ) - pTm->tm_hour ) * 60 );
588 /* Note: 0.1 is hack to ensure seconds come out in whole numbers
589 due to floating point inaccuracies */
590 pTm->tm_sec = (int) (( ( ( decimalPart * 24 * 60 ) - ( pTm->tm_hour * 60 ) - pTm->tm_min ) * 60 ) + 0.1);
592 return TRUE;
597 /******************************************************************************
598 * SizeOfVariantData [INTERNAL]
600 * This function finds the size of the data referenced by a Variant based
601 * the type "vt" of the Variant.
603 static int SizeOfVariantData( VARIANT* parg )
605 int size = 0;
606 switch( V_VT(parg) & VT_TYPEMASK )
608 case( VT_I2 ):
609 size = sizeof(short);
610 break;
611 case( VT_INT ):
612 size = sizeof(int);
613 break;
614 case( VT_I4 ):
615 size = sizeof(long);
616 break;
617 case( VT_UI1 ):
618 size = sizeof(BYTE);
619 break;
620 case( VT_UI2 ):
621 size = sizeof(unsigned short);
622 break;
623 case( VT_UINT ):
624 size = sizeof(unsigned int);
625 break;
626 case( VT_UI4 ):
627 size = sizeof(unsigned long);
628 break;
629 case( VT_R4 ):
630 size = sizeof(float);
631 break;
632 case( VT_R8 ):
633 size = sizeof(double);
634 break;
635 case( VT_DATE ):
636 size = sizeof(DATE);
637 break;
638 case( VT_BOOL ):
639 size = sizeof(VARIANT_BOOL);
640 break;
641 case( VT_BSTR ):
642 case( VT_DISPATCH ):
643 case( VT_UNKNOWN ):
644 size = sizeof(void*);
645 break;
646 case( VT_CY ):
647 size = sizeof(CY);
648 break;
649 case( VT_DECIMAL ): /* hmm, tricky, DECIMAL is only VT_BYREF */
650 default:
651 FIXME("Add size information for type vt=%d\n", V_VT(parg) & VT_TYPEMASK );
652 break;
655 return size;
657 /******************************************************************************
658 * StringDupAtoBstr [INTERNAL]
661 static BSTR StringDupAtoBstr( char* strIn )
663 BSTR bstr = NULL;
664 OLECHAR* pNewString = NULL;
665 pNewString = HEAP_strdupAtoW( GetProcessHeap(), 0, strIn );
666 bstr = SysAllocString( pNewString );
667 HeapFree( GetProcessHeap(), 0, pNewString );
668 return bstr;
671 /******************************************************************************
672 * round [INTERNAL]
674 * Round the double value to the nearest integer value.
676 static double round( double d )
678 double decimals = 0.0, integerValue = 0.0, roundedValue = 0.0;
679 BOOL bEvenNumber = FALSE;
680 int nSign = 0;
682 /* Save the sign of the number
684 nSign = (d >= 0.0) ? 1 : -1;
685 d = fabs( d );
687 /* Remove the decimals.
689 integerValue = floor( d );
691 /* Set the Even flag. This is used to round the number when
692 * the decimals are exactly 1/2. If the integer part is
693 * odd the number is rounded up. If the integer part
694 * is even the number is rounded down. Using this method
695 * numbers are rounded up|down half the time.
697 bEvenNumber = (((short)fmod(integerValue, 2)) == 0) ? TRUE : FALSE;
699 /* Remove the integral part of the number.
701 decimals = d - integerValue;
703 /* Note: Ceil returns the smallest integer that is greater that x.
704 * and floor returns the largest integer that is less than or equal to x.
706 if( decimals > 0.5 )
708 /* If the decimal part is greater than 1/2
710 roundedValue = ceil( d );
712 else if( decimals < 0.5 )
714 /* If the decimal part is smaller than 1/2
716 roundedValue = floor( d );
718 else
720 /* the decimals are exactly 1/2 so round according to
721 * the bEvenNumber flag.
723 if( bEvenNumber )
725 roundedValue = floor( d );
727 else
729 roundedValue = ceil( d );
733 return roundedValue * nSign;
736 /******************************************************************************
737 * RemoveCharacterFromString [INTERNAL]
739 * Removes any of the characters in "strOfCharToRemove" from the "str" argument.
741 static void RemoveCharacterFromString( LPSTR str, LPSTR strOfCharToRemove )
743 LPSTR pNewString = NULL;
744 LPSTR strToken = NULL;
746 /* Check if we have a valid argument
748 if( str != NULL )
750 pNewString = strdup( str );
751 str[0] = '\0';
752 strToken = strtok( pNewString, strOfCharToRemove );
753 while( strToken != NULL ) {
754 strcat( str, strToken );
755 strToken = strtok( NULL, strOfCharToRemove );
757 free( pNewString );
759 return;
762 /******************************************************************************
763 * GetValidRealString [INTERNAL]
765 * Checks if the string is of proper format to be converted to a real value.
767 static BOOL IsValidRealString( LPSTR strRealString )
769 /* Real values that have a decimal point are required to either have
770 * digits before or after the decimal point. We will assume that
771 * we do not have any digits at either position. If we do encounter
772 * some we will disable this flag.
774 BOOL bDigitsRequired = TRUE;
775 /* Processed fields in the string representation of the real number.
777 BOOL bWhiteSpaceProcessed = FALSE;
778 BOOL bFirstSignProcessed = FALSE;
779 BOOL bFirstDigitsProcessed = FALSE;
780 BOOL bDecimalPointProcessed = FALSE;
781 BOOL bSecondDigitsProcessed = FALSE;
782 BOOL bExponentProcessed = FALSE;
783 BOOL bSecondSignProcessed = FALSE;
784 BOOL bThirdDigitsProcessed = FALSE;
785 /* Assume string parameter "strRealString" is valid and try to disprove it.
787 BOOL bValidRealString = TRUE;
789 /* Used to count the number of tokens in the "strRealString".
791 LPSTR strToken = NULL;
792 int nTokens = 0;
793 LPSTR pChar = NULL;
795 /* Check if we have a valid argument
797 if( strRealString == NULL )
799 bValidRealString = FALSE;
802 if( bValidRealString == TRUE )
804 /* Make sure we only have ONE token in the string.
806 strToken = strtok( strRealString, " " );
807 while( strToken != NULL ) {
808 nTokens++;
809 strToken = strtok( NULL, " " );
812 if( nTokens != 1 )
814 bValidRealString = FALSE;
819 /* Make sure this token contains only valid characters.
820 * The string argument to atof has the following form:
821 * [whitespace] [sign] [digits] [.digits] [ {d | D | e | E }[sign]digits]
822 * Whitespace consists of space and|or <TAB> characters, which are ignored.
823 * Sign is either plus '+' or minus '-'.
824 * Digits are one or more decimal digits.
825 * Note: If no digits appear before the decimal point, at least one must
826 * appear after the decimal point.
827 * The decimal digits may be followed by an exponent.
828 * An Exponent consists of an introductory letter ( D, d, E, or e) and
829 * an optionally signed decimal integer.
831 pChar = strRealString;
832 while( bValidRealString == TRUE && *pChar != '\0' )
834 switch( *pChar )
836 /* If whitespace...
838 case ' ':
839 case '\t':
840 if( bWhiteSpaceProcessed ||
841 bFirstSignProcessed ||
842 bFirstDigitsProcessed ||
843 bDecimalPointProcessed ||
844 bSecondDigitsProcessed ||
845 bExponentProcessed ||
846 bSecondSignProcessed ||
847 bThirdDigitsProcessed )
849 bValidRealString = FALSE;
851 break;
852 /* If sign...
854 case '+':
855 case '-':
856 if( bFirstSignProcessed == FALSE )
858 if( bFirstDigitsProcessed ||
859 bDecimalPointProcessed ||
860 bSecondDigitsProcessed ||
861 bExponentProcessed ||
862 bSecondSignProcessed ||
863 bThirdDigitsProcessed )
865 bValidRealString = FALSE;
867 bWhiteSpaceProcessed = TRUE;
868 bFirstSignProcessed = TRUE;
870 else if( bSecondSignProcessed == FALSE )
872 /* Note: The exponent must be present in
873 * order to accept the second sign...
875 if( bExponentProcessed == FALSE ||
876 bThirdDigitsProcessed ||
877 bDigitsRequired )
879 bValidRealString = FALSE;
881 bFirstSignProcessed = TRUE;
882 bWhiteSpaceProcessed = TRUE;
883 bFirstDigitsProcessed = TRUE;
884 bDecimalPointProcessed = TRUE;
885 bSecondDigitsProcessed = TRUE;
886 bSecondSignProcessed = TRUE;
888 break;
890 /* If decimals...
892 case '0':
893 case '1':
894 case '2':
895 case '3':
896 case '4':
897 case '5':
898 case '6':
899 case '7':
900 case '8':
901 case '9':
902 if( bFirstDigitsProcessed == FALSE )
904 if( bDecimalPointProcessed ||
905 bSecondDigitsProcessed ||
906 bExponentProcessed ||
907 bSecondSignProcessed ||
908 bThirdDigitsProcessed )
910 bValidRealString = FALSE;
912 bFirstSignProcessed = TRUE;
913 bWhiteSpaceProcessed = TRUE;
914 /* We have found some digits before the decimal point
915 * so disable the "Digits required" flag.
917 bDigitsRequired = FALSE;
919 else if( bSecondDigitsProcessed == FALSE )
921 if( bExponentProcessed ||
922 bSecondSignProcessed ||
923 bThirdDigitsProcessed )
925 bValidRealString = FALSE;
927 bFirstSignProcessed = TRUE;
928 bWhiteSpaceProcessed = TRUE;
929 bFirstDigitsProcessed = TRUE;
930 bDecimalPointProcessed = TRUE;
931 /* We have found some digits after the decimal point
932 * so disable the "Digits required" flag.
934 bDigitsRequired = FALSE;
936 else if( bThirdDigitsProcessed == FALSE )
938 /* Getting here means everything else should be processed.
939 * If we get anything else than a decimal following this
940 * digit it will be flagged by the other cases, so
941 * we do not really need to do anything in here.
944 break;
945 /* If DecimalPoint...
947 case '.':
948 if( bDecimalPointProcessed ||
949 bSecondDigitsProcessed ||
950 bExponentProcessed ||
951 bSecondSignProcessed ||
952 bThirdDigitsProcessed )
954 bValidRealString = FALSE;
956 bFirstSignProcessed = TRUE;
957 bWhiteSpaceProcessed = TRUE;
958 bFirstDigitsProcessed = TRUE;
959 bDecimalPointProcessed = TRUE;
960 break;
961 /* If Exponent...
963 case 'e':
964 case 'E':
965 case 'd':
966 case 'D':
967 if( bExponentProcessed ||
968 bSecondSignProcessed ||
969 bThirdDigitsProcessed ||
970 bDigitsRequired )
972 bValidRealString = FALSE;
974 bFirstSignProcessed = TRUE;
975 bWhiteSpaceProcessed = TRUE;
976 bFirstDigitsProcessed = TRUE;
977 bDecimalPointProcessed = TRUE;
978 bSecondDigitsProcessed = TRUE;
979 bExponentProcessed = TRUE;
980 break;
981 default:
982 bValidRealString = FALSE;
983 break;
985 /* Process next character.
987 pChar++;
990 /* If the required digits were not present we have an invalid
991 * string representation of a real number.
993 if( bDigitsRequired == TRUE )
995 bValidRealString = FALSE;
998 return bValidRealString;
1002 /******************************************************************************
1003 * Coerce [INTERNAL]
1005 * This function dispatches execution to the proper conversion API
1006 * to do the necessary coercion.
1008 * FIXME: Passing down dwFlags to the conversion functions is wrong, this
1009 * is a different flagmask. Check MSDN.
1011 static HRESULT Coerce( VARIANTARG* pd, LCID lcid, ULONG dwFlags, VARIANTARG* ps, VARTYPE vt )
1013 HRESULT res = S_OK;
1014 unsigned short vtFrom = 0;
1015 vtFrom = V_VT(ps) & VT_TYPEMASK;
1018 /* Note: Since "long" and "int" values both have 4 bytes and are
1019 * both signed integers "int" will be treated as "long" in the
1020 * following code.
1021 * The same goes for their unsigned versions.
1024 /* Trivial Case: If the coercion is from two types that are
1025 * identical then we can blindly copy from one argument to another.*/
1026 if ((vt==vtFrom))
1028 return VariantCopy(pd,ps);
1031 /* Cases requiring thought*/
1032 switch( vt )
1035 case( VT_EMPTY ):
1036 res = VariantClear( pd );
1037 break;
1038 case( VT_NULL ):
1039 res = VariantClear( pd );
1040 if( res == S_OK )
1042 V_VT(pd) = VT_NULL;
1044 break;
1045 case( VT_I1 ):
1046 switch( vtFrom )
1048 case( VT_I1 ):
1049 res = VariantCopy( pd, ps );
1050 break;
1051 case( VT_I2 ):
1052 res = VarI1FromI2( V_UNION(ps,iVal), &V_UNION(pd,cVal) );
1053 break;
1054 case( VT_INT ):
1055 case( VT_I4 ):
1056 res = VarI1FromI4( V_UNION(ps,lVal), &V_UNION(pd,cVal) );
1057 break;
1058 case( VT_UI1 ):
1059 res = VarI1FromUI1( V_UNION(ps,bVal), &V_UNION(pd,cVal) );
1060 break;
1061 case( VT_UI2 ):
1062 res = VarI1FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,cVal) );
1063 break;
1064 case( VT_UINT ):
1065 case( VT_UI4 ):
1066 res = VarI1FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,cVal) );
1067 break;
1068 case( VT_R4 ):
1069 res = VarI1FromR4( V_UNION(ps,fltVal), &V_UNION(pd,cVal) );
1070 break;
1071 case( VT_R8 ):
1072 res = VarI1FromR8( V_UNION(ps,dblVal), &V_UNION(pd,cVal) );
1073 break;
1074 case( VT_DATE ):
1075 res = VarI1FromDate( V_UNION(ps,date), &V_UNION(pd,cVal) );
1076 break;
1077 case( VT_BOOL ):
1078 res = VarI1FromBool( V_UNION(ps,boolVal), &V_UNION(pd,cVal) );
1079 break;
1080 case( VT_BSTR ):
1081 res = VarI1FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,cVal) );
1082 break;
1083 case( VT_CY ):
1084 res = VarI1FromCy( V_UNION(ps,cyVal), &V_UNION(pd,cVal) );
1085 break;
1086 case( VT_DISPATCH ):
1087 /*res = VarI1FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,cVal) );*/
1088 case( VT_DECIMAL ):
1089 /*res = VarI1FromDec( V_UNION(ps,decVal), &V_UNION(pd,cVal) );*/
1090 case( VT_UNKNOWN ):
1091 default:
1092 res = DISP_E_TYPEMISMATCH;
1093 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1094 break;
1096 break;
1098 case( VT_I2 ):
1099 switch( vtFrom )
1101 case( VT_I1 ):
1102 res = VarI2FromI1( V_UNION(ps,cVal), &V_UNION(pd,iVal) );
1103 break;
1104 case( VT_I2 ):
1105 res = VariantCopy( pd, ps );
1106 break;
1107 case( VT_INT ):
1108 case( VT_I4 ):
1109 res = VarI2FromI4( V_UNION(ps,lVal), &V_UNION(pd,iVal) );
1110 break;
1111 case( VT_UI1 ):
1112 res = VarI2FromUI1( V_UNION(ps,bVal), &V_UNION(pd,iVal) );
1113 break;
1114 case( VT_UI2 ):
1115 res = VarI2FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,iVal) );
1116 break;
1117 case( VT_UINT ):
1118 case( VT_UI4 ):
1119 res = VarI2FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,iVal) );
1120 break;
1121 case( VT_R4 ):
1122 res = VarI2FromR4( V_UNION(ps,fltVal), &V_UNION(pd,iVal) );
1123 break;
1124 case( VT_R8 ):
1125 res = VarI2FromR8( V_UNION(ps,dblVal), &V_UNION(pd,iVal) );
1126 break;
1127 case( VT_DATE ):
1128 res = VarI2FromDate( V_UNION(ps,date), &V_UNION(pd,iVal) );
1129 break;
1130 case( VT_BOOL ):
1131 res = VarI2FromBool( V_UNION(ps,boolVal), &V_UNION(pd,iVal) );
1132 break;
1133 case( VT_BSTR ):
1134 res = VarI2FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,iVal) );
1135 break;
1136 case( VT_CY ):
1137 res = VarI2FromCy( V_UNION(ps,cyVal), &V_UNION(pd,iVal) );
1138 break;
1139 case( VT_DISPATCH ):
1140 /*res = VarI2FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,iVal) );*/
1141 case( VT_DECIMAL ):
1142 /*res = VarI2FromDec( V_UNION(ps,deiVal), &V_UNION(pd,iVal) );*/
1143 case( VT_UNKNOWN ):
1144 default:
1145 res = DISP_E_TYPEMISMATCH;
1146 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1147 break;
1149 break;
1151 case( VT_INT ):
1152 case( VT_I4 ):
1153 switch( vtFrom )
1155 case( VT_EMPTY ):
1156 V_UNION(pd,lVal) = 0;
1157 res = S_OK;
1158 break;
1159 case( VT_I1 ):
1160 res = VarI4FromI1( V_UNION(ps,cVal), &V_UNION(pd,lVal) );
1161 break;
1162 case( VT_I2 ):
1163 res = VarI4FromI2( V_UNION(ps,iVal), &V_UNION(pd,lVal) );
1164 break;
1165 case( VT_INT ):
1166 case( VT_I4 ):
1167 res = VariantCopy( pd, ps );
1168 break;
1169 case( VT_UI1 ):
1170 res = VarI4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,lVal) );
1171 break;
1172 case( VT_UI2 ):
1173 res = VarI4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,lVal) );
1174 break;
1175 case( VT_UINT ):
1176 case( VT_UI4 ):
1177 res = VarI4FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,lVal) );
1178 break;
1179 case( VT_R4 ):
1180 res = VarI4FromR4( V_UNION(ps,fltVal), &V_UNION(pd,lVal) );
1181 break;
1182 case( VT_R8 ):
1183 res = VarI4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,lVal) );
1184 break;
1185 case( VT_DATE ):
1186 res = VarI4FromDate( V_UNION(ps,date), &V_UNION(pd,lVal) );
1187 break;
1188 case( VT_BOOL ):
1189 res = VarI4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,lVal) );
1190 break;
1191 case( VT_BSTR ):
1192 res = VarI4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,lVal) );
1193 break;
1194 case( VT_CY ):
1195 res = VarI4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,lVal) );
1196 break;
1197 case( VT_DISPATCH ):
1198 /*res = VarI4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,lVal) );*/
1199 case( VT_DECIMAL ):
1200 /*res = VarI4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,lVal) );*/
1201 case( VT_UNKNOWN ):
1202 default:
1203 res = DISP_E_TYPEMISMATCH;
1204 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1205 break;
1207 break;
1209 case( VT_UI1 ):
1210 switch( vtFrom )
1212 case( VT_I1 ):
1213 res = VarUI1FromI1( V_UNION(ps,cVal), &V_UNION(pd,bVal) );
1214 break;
1215 case( VT_I2 ):
1216 res = VarUI1FromI2( V_UNION(ps,iVal), &V_UNION(pd,bVal) );
1217 break;
1218 case( VT_INT ):
1219 case( VT_I4 ):
1220 res = VarUI1FromI4( V_UNION(ps,lVal), &V_UNION(pd,bVal) );
1221 break;
1222 case( VT_UI1 ):
1223 res = VariantCopy( pd, ps );
1224 break;
1225 case( VT_UI2 ):
1226 res = VarUI1FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,bVal) );
1227 break;
1228 case( VT_UINT ):
1229 case( VT_UI4 ):
1230 res = VarUI1FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,bVal) );
1231 break;
1232 case( VT_R4 ):
1233 res = VarUI1FromR4( V_UNION(ps,fltVal), &V_UNION(pd,bVal) );
1234 break;
1235 case( VT_R8 ):
1236 res = VarUI1FromR8( V_UNION(ps,dblVal), &V_UNION(pd,bVal) );
1237 break;
1238 case( VT_DATE ):
1239 res = VarUI1FromDate( V_UNION(ps,date), &V_UNION(pd,bVal) );
1240 break;
1241 case( VT_BOOL ):
1242 res = VarUI1FromBool( V_UNION(ps,boolVal), &V_UNION(pd,bVal) );
1243 break;
1244 case( VT_BSTR ):
1245 res = VarUI1FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,bVal) );
1246 break;
1247 case( VT_CY ):
1248 res = VarUI1FromCy( V_UNION(ps,cyVal), &V_UNION(pd,bVal) );
1249 break;
1250 case( VT_DISPATCH ):
1251 /*res = VarUI1FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,bVal) );*/
1252 case( VT_DECIMAL ):
1253 /*res = VarUI1FromDec( V_UNION(ps,deiVal), &V_UNION(pd,bVal) );*/
1254 case( VT_UNKNOWN ):
1255 default:
1256 res = DISP_E_TYPEMISMATCH;
1257 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1258 break;
1260 break;
1262 case( VT_UI2 ):
1263 switch( vtFrom )
1265 case( VT_I1 ):
1266 res = VarUI2FromI1( V_UNION(ps,cVal), &V_UNION(pd,uiVal) );
1267 break;
1268 case( VT_I2 ):
1269 res = VarUI2FromI2( V_UNION(ps,iVal), &V_UNION(pd,uiVal) );
1270 break;
1271 case( VT_INT ):
1272 case( VT_I4 ):
1273 res = VarUI2FromI4( V_UNION(ps,lVal), &V_UNION(pd,uiVal) );
1274 break;
1275 case( VT_UI1 ):
1276 res = VarUI2FromUI1( V_UNION(ps,bVal), &V_UNION(pd,uiVal) );
1277 break;
1278 case( VT_UI2 ):
1279 res = VariantCopy( pd, ps );
1280 break;
1281 case( VT_UINT ):
1282 case( VT_UI4 ):
1283 res = VarUI2FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,uiVal) );
1284 break;
1285 case( VT_R4 ):
1286 res = VarUI2FromR4( V_UNION(ps,fltVal), &V_UNION(pd,uiVal) );
1287 break;
1288 case( VT_R8 ):
1289 res = VarUI2FromR8( V_UNION(ps,dblVal), &V_UNION(pd,uiVal) );
1290 break;
1291 case( VT_DATE ):
1292 res = VarUI2FromDate( V_UNION(ps,date), &V_UNION(pd,uiVal) );
1293 break;
1294 case( VT_BOOL ):
1295 res = VarUI2FromBool( V_UNION(ps,boolVal), &V_UNION(pd,uiVal) );
1296 break;
1297 case( VT_BSTR ):
1298 res = VarUI2FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,uiVal) );
1299 break;
1300 case( VT_CY ):
1301 res = VarUI2FromCy( V_UNION(ps,cyVal), &V_UNION(pd,uiVal) );
1302 break;
1303 case( VT_DISPATCH ):
1304 /*res = VarUI2FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,uiVal) );*/
1305 case( VT_DECIMAL ):
1306 /*res = VarUI2FromDec( V_UNION(ps,deiVal), &V_UNION(pd,uiVal) );*/
1307 case( VT_UNKNOWN ):
1308 default:
1309 res = DISP_E_TYPEMISMATCH;
1310 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1311 break;
1313 break;
1315 case( VT_UINT ):
1316 case( VT_UI4 ):
1317 switch( vtFrom )
1319 case( VT_I1 ):
1320 res = VarUI4FromI1( V_UNION(ps,cVal), &V_UNION(pd,ulVal) );
1321 break;
1322 case( VT_I2 ):
1323 res = VarUI4FromI2( V_UNION(ps,iVal), &V_UNION(pd,ulVal) );
1324 break;
1325 case( VT_INT ):
1326 case( VT_I4 ):
1327 res = VarUI4FromI4( V_UNION(ps,lVal), &V_UNION(pd,ulVal) );
1328 break;
1329 case( VT_UI1 ):
1330 res = VarUI4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,ulVal) );
1331 break;
1332 case( VT_UI2 ):
1333 res = VarUI4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,ulVal) );
1334 break;
1335 case( VT_UI4 ):
1336 res = VariantCopy( pd, ps );
1337 break;
1338 case( VT_R4 ):
1339 res = VarUI4FromR4( V_UNION(ps,fltVal), &V_UNION(pd,ulVal) );
1340 break;
1341 case( VT_R8 ):
1342 res = VarUI4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,ulVal) );
1343 break;
1344 case( VT_DATE ):
1345 res = VarUI4FromDate( V_UNION(ps,date), &V_UNION(pd,ulVal) );
1346 break;
1347 case( VT_BOOL ):
1348 res = VarUI4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,ulVal) );
1349 break;
1350 case( VT_BSTR ):
1351 res = VarUI4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,ulVal) );
1352 break;
1353 case( VT_CY ):
1354 res = VarUI4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,ulVal) );
1355 break;
1356 case( VT_DISPATCH ):
1357 /*res = VarUI4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,ulVal) );*/
1358 case( VT_DECIMAL ):
1359 /*res = VarUI4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,ulVal) );*/
1360 case( VT_UNKNOWN ):
1361 default:
1362 res = DISP_E_TYPEMISMATCH;
1363 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1364 break;
1366 break;
1368 case( VT_R4 ):
1369 switch( vtFrom )
1371 case( VT_I1 ):
1372 res = VarR4FromI1( V_UNION(ps,cVal), &V_UNION(pd,fltVal) );
1373 break;
1374 case( VT_I2 ):
1375 res = VarR4FromI2( V_UNION(ps,iVal), &V_UNION(pd,fltVal) );
1376 break;
1377 case( VT_INT ):
1378 case( VT_I4 ):
1379 res = VarR4FromI4( V_UNION(ps,lVal), &V_UNION(pd,fltVal) );
1380 break;
1381 case( VT_UI1 ):
1382 res = VarR4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,fltVal) );
1383 break;
1384 case( VT_UI2 ):
1385 res = VarR4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,fltVal) );
1386 break;
1387 case( VT_UINT ):
1388 case( VT_UI4 ):
1389 res = VarR4FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,fltVal) );
1390 break;
1391 case( VT_R4 ):
1392 res = VariantCopy( pd, ps );
1393 break;
1394 case( VT_R8 ):
1395 res = VarR4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,fltVal) );
1396 break;
1397 case( VT_DATE ):
1398 res = VarR4FromDate( V_UNION(ps,date), &V_UNION(pd,fltVal) );
1399 break;
1400 case( VT_BOOL ):
1401 res = VarR4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,fltVal) );
1402 break;
1403 case( VT_BSTR ):
1404 res = VarR4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,fltVal) );
1405 break;
1406 case( VT_CY ):
1407 res = VarR4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,fltVal) );
1408 break;
1409 case( VT_DISPATCH ):
1410 /*res = VarR4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,fltVal) );*/
1411 case( VT_DECIMAL ):
1412 /*res = VarR4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,fltVal) );*/
1413 case( VT_UNKNOWN ):
1414 default:
1415 res = DISP_E_TYPEMISMATCH;
1416 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1417 break;
1419 break;
1421 case( VT_R8 ):
1422 switch( vtFrom )
1424 case( VT_I1 ):
1425 res = VarR8FromI1( V_UNION(ps,cVal), &V_UNION(pd,dblVal) );
1426 break;
1427 case( VT_I2 ):
1428 res = VarR8FromI2( V_UNION(ps,iVal), &V_UNION(pd,dblVal) );
1429 break;
1430 case( VT_INT ):
1431 case( VT_I4 ):
1432 res = VarR8FromI4( V_UNION(ps,lVal), &V_UNION(pd,dblVal) );
1433 break;
1434 case( VT_UI1 ):
1435 res = VarR8FromUI1( V_UNION(ps,bVal), &V_UNION(pd,dblVal) );
1436 break;
1437 case( VT_UI2 ):
1438 res = VarR8FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,dblVal) );
1439 break;
1440 case( VT_UINT ):
1441 case( VT_UI4 ):
1442 res = VarR8FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,dblVal) );
1443 break;
1444 case( VT_R4 ):
1445 res = VarR8FromR4( V_UNION(ps,fltVal), &V_UNION(pd,dblVal) );
1446 break;
1447 case( VT_R8 ):
1448 res = VariantCopy( pd, ps );
1449 break;
1450 case( VT_DATE ):
1451 res = VarR8FromDate( V_UNION(ps,date), &V_UNION(pd,dblVal) );
1452 break;
1453 case( VT_BOOL ):
1454 res = VarR8FromBool( V_UNION(ps,boolVal), &V_UNION(pd,dblVal) );
1455 break;
1456 case( VT_BSTR ):
1457 res = VarR8FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,dblVal) );
1458 break;
1459 case( VT_CY ):
1460 res = VarR8FromCy( V_UNION(ps,cyVal), &V_UNION(pd,dblVal) );
1461 break;
1462 case( VT_DISPATCH ):
1463 /*res = VarR8FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,dblVal) );*/
1464 case( VT_DECIMAL ):
1465 /*res = VarR8FromDec( V_UNION(ps,deiVal), &V_UNION(pd,dblVal) );*/
1466 case( VT_UNKNOWN ):
1467 default:
1468 res = DISP_E_TYPEMISMATCH;
1469 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1470 break;
1472 break;
1474 case( VT_DATE ):
1475 switch( vtFrom )
1477 case( VT_I1 ):
1478 res = VarDateFromI1( V_UNION(ps,cVal), &V_UNION(pd,date) );
1479 break;
1480 case( VT_I2 ):
1481 res = VarDateFromI2( V_UNION(ps,iVal), &V_UNION(pd,date) );
1482 break;
1483 case( VT_INT ):
1484 res = VarDateFromInt( V_UNION(ps,intVal), &V_UNION(pd,date) );
1485 break;
1486 case( VT_I4 ):
1487 res = VarDateFromI4( V_UNION(ps,lVal), &V_UNION(pd,date) );
1488 break;
1489 case( VT_UI1 ):
1490 res = VarDateFromUI1( V_UNION(ps,bVal), &V_UNION(pd,date) );
1491 break;
1492 case( VT_UI2 ):
1493 res = VarDateFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,date) );
1494 break;
1495 case( VT_UINT ):
1496 res = VarDateFromUint( V_UNION(ps,uintVal), &V_UNION(pd,date) );
1497 break;
1498 case( VT_UI4 ):
1499 res = VarDateFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,date) );
1500 break;
1501 case( VT_R4 ):
1502 res = VarDateFromR4( V_UNION(ps,fltVal), &V_UNION(pd,date) );
1503 break;
1504 case( VT_R8 ):
1505 res = VarDateFromR8( V_UNION(ps,dblVal), &V_UNION(pd,date) );
1506 break;
1507 case( VT_DATE ):
1508 res = VariantCopy( pd, ps );
1509 break;
1510 case( VT_BOOL ):
1511 res = VarDateFromBool( V_UNION(ps,boolVal), &V_UNION(pd,date) );
1512 break;
1513 case( VT_BSTR ):
1514 res = VarDateFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,date) );
1515 break;
1516 case( VT_CY ):
1517 res = VarDateFromCy( V_UNION(ps,cyVal), &V_UNION(pd,date) );
1518 break;
1519 case( VT_DISPATCH ):
1520 /*res = VarDateFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,date) );*/
1521 case( VT_DECIMAL ):
1522 /*res = VarDateFromDec( V_UNION(ps,deiVal), &V_UNION(pd,date) );*/
1523 case( VT_UNKNOWN ):
1524 default:
1525 res = DISP_E_TYPEMISMATCH;
1526 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1527 break;
1529 break;
1531 case( VT_BOOL ):
1532 switch( vtFrom )
1534 case( VT_EMPTY ):
1535 res = S_OK;
1536 V_UNION(pd,boolVal) = VARIANT_FALSE;
1537 break;
1538 case( VT_I1 ):
1539 res = VarBoolFromI1( V_UNION(ps,cVal), &V_UNION(pd,boolVal) );
1540 break;
1541 case( VT_I2 ):
1542 res = VarBoolFromI2( V_UNION(ps,iVal), &V_UNION(pd,boolVal) );
1543 break;
1544 case( VT_INT ):
1545 res = VarBoolFromInt( V_UNION(ps,intVal), &V_UNION(pd,boolVal) );
1546 break;
1547 case( VT_I4 ):
1548 res = VarBoolFromI4( V_UNION(ps,lVal), &V_UNION(pd,boolVal) );
1549 break;
1550 case( VT_UI1 ):
1551 res = VarBoolFromUI1( V_UNION(ps,bVal), &V_UNION(pd,boolVal) );
1552 break;
1553 case( VT_UI2 ):
1554 res = VarBoolFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,boolVal) );
1555 break;
1556 case( VT_UINT ):
1557 res = VarBoolFromUint( V_UNION(ps,uintVal), &V_UNION(pd,boolVal) );
1558 break;
1559 case( VT_UI4 ):
1560 res = VarBoolFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,boolVal) );
1561 break;
1562 case( VT_R4 ):
1563 res = VarBoolFromR4( V_UNION(ps,fltVal), &V_UNION(pd,boolVal) );
1564 break;
1565 case( VT_R8 ):
1566 res = VarBoolFromR8( V_UNION(ps,dblVal), &V_UNION(pd,boolVal) );
1567 break;
1568 case( VT_DATE ):
1569 res = VarBoolFromDate( V_UNION(ps,date), &V_UNION(pd,boolVal) );
1570 break;
1571 case( VT_BOOL ):
1572 res = VariantCopy( pd, ps );
1573 break;
1574 case( VT_BSTR ):
1575 res = VarBoolFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,boolVal) );
1576 break;
1577 case( VT_CY ):
1578 res = VarBoolFromCy( V_UNION(ps,cyVal), &V_UNION(pd,boolVal) );
1579 break;
1580 case( VT_DISPATCH ):
1581 /*res = VarBoolFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,boolVal) );*/
1582 case( VT_DECIMAL ):
1583 /*res = VarBoolFromDec( V_UNION(ps,deiVal), &V_UNION(pd,boolVal) );*/
1584 case( VT_UNKNOWN ):
1585 default:
1586 res = DISP_E_TYPEMISMATCH;
1587 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1588 break;
1590 break;
1592 case( VT_BSTR ):
1593 switch( vtFrom )
1595 case( VT_EMPTY ):
1596 if ((V_UNION(pd,bstrVal) = SysAllocStringLen(NULL, 0)))
1597 res = S_OK;
1598 else
1599 res = E_OUTOFMEMORY;
1600 break;
1601 case( VT_I1 ):
1602 res = VarBstrFromI1( V_UNION(ps,cVal), lcid, 0, &V_UNION(pd,bstrVal) );
1603 break;
1604 case( VT_I2 ):
1605 res = VarBstrFromI2( V_UNION(ps,iVal), lcid, 0, &V_UNION(pd,bstrVal) );
1606 break;
1607 case( VT_INT ):
1608 res = VarBstrFromInt( V_UNION(ps,intVal), lcid, 0, &V_UNION(pd,bstrVal) );
1609 break;
1610 case( VT_I4 ):
1611 res = VarBstrFromI4( V_UNION(ps,lVal), lcid, 0, &V_UNION(pd,bstrVal) );
1612 break;
1613 case( VT_UI1 ):
1614 res = VarBstrFromUI1( V_UNION(ps,bVal), lcid, 0, &V_UNION(pd,bstrVal) );
1615 break;
1616 case( VT_UI2 ):
1617 res = VarBstrFromUI2( V_UNION(ps,uiVal), lcid, 0, &V_UNION(pd,bstrVal) );
1618 break;
1619 case( VT_UINT ):
1620 res = VarBstrFromUint( V_UNION(ps,uintVal), lcid, 0, &V_UNION(pd,bstrVal) );
1621 break;
1622 case( VT_UI4 ):
1623 res = VarBstrFromUI4( V_UNION(ps,ulVal), lcid, 0, &V_UNION(pd,bstrVal) );
1624 break;
1625 case( VT_R4 ):
1626 res = VarBstrFromR4( V_UNION(ps,fltVal), lcid, 0, &V_UNION(pd,bstrVal) );
1627 break;
1628 case( VT_R8 ):
1629 res = VarBstrFromR8( V_UNION(ps,dblVal), lcid, 0, &V_UNION(pd,bstrVal) );
1630 break;
1631 case( VT_DATE ):
1632 res = VarBstrFromDate( V_UNION(ps,date), lcid, 0, &V_UNION(pd,bstrVal) );
1633 break;
1634 case( VT_BOOL ):
1635 res = VarBstrFromBool( V_UNION(ps,boolVal), lcid, 0, &V_UNION(pd,bstrVal) );
1636 break;
1637 case( VT_BSTR ):
1638 res = VariantCopy( pd, ps );
1639 break;
1640 case( VT_CY ):
1641 res = VarBstrFromCy( V_UNION(ps,cyVal), lcid, 0, &V_UNION(pd,bstrVal) );
1642 break;
1643 case( VT_DISPATCH ):
1644 /*res = VarBstrFromDisp( V_UNION(ps,pdispVal), lcid, 0, &(pd,bstrVal) );*/
1645 case( VT_DECIMAL ):
1646 /*res = VarBstrFromDec( V_UNION(ps,deiVal), lcid, 0, &(pd,bstrVal) );*/
1647 case( VT_UNKNOWN ):
1648 default:
1649 res = DISP_E_TYPEMISMATCH;
1650 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1651 break;
1653 break;
1655 case( VT_CY ):
1656 switch( vtFrom )
1658 case( VT_I1 ):
1659 res = VarCyFromI1( V_UNION(ps,cVal), &V_UNION(pd,cyVal) );
1660 break;
1661 case( VT_I2 ):
1662 res = VarCyFromI2( V_UNION(ps,iVal), &V_UNION(pd,cyVal) );
1663 break;
1664 case( VT_INT ):
1665 res = VarCyFromInt( V_UNION(ps,intVal), &V_UNION(pd,cyVal) );
1666 break;
1667 case( VT_I4 ):
1668 res = VarCyFromI4( V_UNION(ps,lVal), &V_UNION(pd,cyVal) );
1669 break;
1670 case( VT_UI1 ):
1671 res = VarCyFromUI1( V_UNION(ps,bVal), &V_UNION(pd,cyVal) );
1672 break;
1673 case( VT_UI2 ):
1674 res = VarCyFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,cyVal) );
1675 break;
1676 case( VT_UINT ):
1677 res = VarCyFromUint( V_UNION(ps,uintVal), &V_UNION(pd,cyVal) );
1678 break;
1679 case( VT_UI4 ):
1680 res = VarCyFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,cyVal) );
1681 break;
1682 case( VT_R4 ):
1683 res = VarCyFromR4( V_UNION(ps,fltVal), &V_UNION(pd,cyVal) );
1684 break;
1685 case( VT_R8 ):
1686 res = VarCyFromR8( V_UNION(ps,dblVal), &V_UNION(pd,cyVal) );
1687 break;
1688 case( VT_DATE ):
1689 res = VarCyFromDate( V_UNION(ps,date), &V_UNION(pd,cyVal) );
1690 break;
1691 case( VT_BOOL ):
1692 res = VarCyFromBool( V_UNION(ps,date), &V_UNION(pd,cyVal) );
1693 break;
1694 case( VT_CY ):
1695 res = VariantCopy( pd, ps );
1696 break;
1697 case( VT_BSTR ):
1698 res = VarCyFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,cyVal) );
1699 break;
1700 case( VT_DISPATCH ):
1701 /*res = VarCyFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,cyVal) );*/
1702 case( VT_DECIMAL ):
1703 /*res = VarCyFromDec( V_UNION(ps,deiVal), &V_UNION(pd,cyVal) );*/
1704 break;
1705 case( VT_UNKNOWN ):
1706 default:
1707 res = DISP_E_TYPEMISMATCH;
1708 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1709 break;
1711 break;
1713 case( VT_UNKNOWN ):
1714 if (vtFrom == VT_DISPATCH)
1716 res = IDispatch_QueryInterface(V_DISPATCH(ps), &IID_IUnknown, (LPVOID*)&V_UNKNOWN(pd));
1718 else
1720 res = DISP_E_TYPEMISMATCH;
1721 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1723 break;
1725 default:
1726 res = DISP_E_TYPEMISMATCH;
1727 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1728 break;
1731 return res;
1734 /******************************************************************************
1735 * ValidateVtRange [INTERNAL]
1737 * Used internally by the hi-level Variant API to determine
1738 * if the vartypes are valid.
1740 static HRESULT WINAPI ValidateVtRange( VARTYPE vt )
1742 /* if by value we must make sure it is in the
1743 * range of the valid types.
1745 if( ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1747 return DISP_E_BADVARTYPE;
1749 return S_OK;
1753 /******************************************************************************
1754 * ValidateVartype [INTERNAL]
1756 * Used internally by the hi-level Variant API to determine
1757 * if the vartypes are valid.
1759 static HRESULT WINAPI ValidateVariantType( VARTYPE vt )
1761 HRESULT res = S_OK;
1763 /* check if we have a valid argument.
1765 if( vt & VT_BYREF )
1767 /* if by reference check that the type is in
1768 * the valid range and that it is not of empty or null type
1770 if( ( vt & VT_TYPEMASK ) == VT_EMPTY ||
1771 ( vt & VT_TYPEMASK ) == VT_NULL ||
1772 ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1774 res = DISP_E_BADVARTYPE;
1778 else
1780 res = ValidateVtRange( vt );
1783 return res;
1786 /******************************************************************************
1787 * ValidateVt [INTERNAL]
1789 * Used internally by the hi-level Variant API to determine
1790 * if the vartypes are valid.
1792 static HRESULT WINAPI ValidateVt( VARTYPE vt )
1794 HRESULT res = S_OK;
1796 /* check if we have a valid argument.
1798 if( vt & VT_BYREF )
1800 /* if by reference check that the type is in
1801 * the valid range and that it is not of empty or null type
1803 if( ( vt & VT_TYPEMASK ) == VT_EMPTY ||
1804 ( vt & VT_TYPEMASK ) == VT_NULL ||
1805 ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1807 res = DISP_E_BADVARTYPE;
1811 else
1813 res = ValidateVtRange( vt );
1816 return res;
1823 /******************************************************************************
1824 * VariantInit [OLEAUT32.8]
1826 * Initializes the Variant. Unlike VariantClear it does not interpret
1827 * the current contents of the Variant.
1829 void WINAPI VariantInit(VARIANTARG* pvarg)
1831 TRACE("(%p)\n",pvarg);
1833 memset(pvarg, 0, sizeof (VARIANTARG));
1834 V_VT(pvarg) = VT_EMPTY;
1836 return;
1839 /******************************************************************************
1840 * VariantClear [OLEAUT32.9]
1842 * This function clears the VARIANT by setting the vt field to VT_EMPTY. It also
1843 * sets the wReservedX field to 0. The current contents of the VARIANT are
1844 * freed. If the vt is VT_BSTR the string is freed. If VT_DISPATCH the object is
1845 * released. If VT_ARRAY the array is freed.
1847 HRESULT WINAPI VariantClear(VARIANTARG* pvarg)
1849 HRESULT res = S_OK;
1850 TRACE("(%p)\n",pvarg);
1852 res = ValidateVariantType( V_VT(pvarg) );
1853 if( res == S_OK )
1855 if( !( V_VT(pvarg) & VT_BYREF ) )
1858 * The VT_ARRAY flag is a special case of a safe array.
1860 if ( (V_VT(pvarg) & VT_ARRAY) != 0)
1862 SafeArrayDestroy(V_UNION(pvarg,parray));
1864 else
1866 switch( V_VT(pvarg) & VT_TYPEMASK )
1868 case( VT_BSTR ):
1869 SysFreeString( V_UNION(pvarg,bstrVal) );
1870 break;
1871 case( VT_DISPATCH ):
1872 if(V_UNION(pvarg,pdispVal)!=NULL)
1873 ICOM_CALL(Release,V_UNION(pvarg,pdispVal));
1874 break;
1875 case( VT_VARIANT ):
1876 VariantClear(V_UNION(pvarg,pvarVal));
1877 break;
1878 case( VT_UNKNOWN ):
1879 if(V_UNION(pvarg,punkVal)!=NULL)
1880 ICOM_CALL(Release,V_UNION(pvarg,punkVal));
1881 break;
1882 case( VT_SAFEARRAY ):
1883 SafeArrayDestroy(V_UNION(pvarg,parray));
1884 break;
1885 default:
1886 break;
1892 * Empty all the fields and mark the type as empty.
1894 memset(pvarg, 0, sizeof (VARIANTARG));
1895 V_VT(pvarg) = VT_EMPTY;
1898 return res;
1901 /******************************************************************************
1902 * VariantCopy [OLEAUT32.10]
1904 * Frees up the designation variant and makes a copy of the source.
1906 HRESULT WINAPI VariantCopy(VARIANTARG* pvargDest, VARIANTARG* pvargSrc)
1908 HRESULT res = S_OK;
1910 TRACE("(%p, %p), vt=%d\n", pvargDest, pvargSrc, V_VT(pvargSrc));
1912 res = ValidateVariantType( V_VT(pvargSrc) );
1914 /* If the pointer are to the same variant we don't need
1915 * to do anything.
1917 if( pvargDest != pvargSrc && res == S_OK )
1919 res = VariantClear( pvargDest );
1921 if( res == S_OK )
1923 if( V_VT(pvargSrc) & VT_BYREF )
1925 /* In the case of byreference we only need
1926 * to copy the pointer.
1928 pvargDest->n1.n2.n3 = pvargSrc->n1.n2.n3;
1929 V_VT(pvargDest) = V_VT(pvargSrc);
1931 else
1934 * The VT_ARRAY flag is another way to designate a safe array.
1936 if (V_VT(pvargSrc) & VT_ARRAY)
1938 SafeArrayCopy(V_UNION(pvargSrc,parray), &V_UNION(pvargDest,parray));
1940 else
1942 /* In the case of by value we need to
1943 * copy the actual value. In the case of
1944 * VT_BSTR a copy of the string is made,
1945 * if VT_DISPATCH or VT_IUNKNOWN AddRef is
1946 * called to increment the object's reference count.
1948 switch( V_VT(pvargSrc) & VT_TYPEMASK )
1950 case( VT_BSTR ):
1951 V_UNION(pvargDest,bstrVal) = SYSDUPSTRING( V_UNION(pvargSrc,bstrVal) );
1952 break;
1953 case( VT_DISPATCH ):
1954 V_UNION(pvargDest,pdispVal) = V_UNION(pvargSrc,pdispVal);
1955 if (V_UNION(pvargDest,pdispVal)!=NULL)
1956 ICOM_CALL(AddRef,V_UNION(pvargDest,pdispVal));
1957 break;
1958 case( VT_VARIANT ):
1959 VariantCopy(V_UNION(pvargDest,pvarVal),V_UNION(pvargSrc,pvarVal));
1960 break;
1961 case( VT_UNKNOWN ):
1962 V_UNION(pvargDest,punkVal) = V_UNION(pvargSrc,punkVal);
1963 if (V_UNION(pvargDest,pdispVal)!=NULL)
1964 ICOM_CALL(AddRef,V_UNION(pvargDest,punkVal));
1965 break;
1966 case( VT_SAFEARRAY ):
1967 SafeArrayCopy(V_UNION(pvargSrc,parray), &V_UNION(pvargDest,parray));
1968 break;
1969 default:
1970 pvargDest->n1.n2.n3 = pvargSrc->n1.n2.n3;
1971 break;
1975 V_VT(pvargDest) = V_VT(pvargSrc);
1980 return res;
1984 /******************************************************************************
1985 * VariantCopyInd [OLEAUT32.11]
1987 * Frees up the destination variant and makes a copy of the source. If
1988 * the source is of type VT_BYREF it performs the necessary indirections.
1990 HRESULT WINAPI VariantCopyInd(VARIANT* pvargDest, VARIANTARG* pvargSrc)
1992 HRESULT res = S_OK;
1994 TRACE("(%p, %p)\n", pvargDest, pvargSrc);
1996 res = ValidateVariantType( V_VT(pvargSrc) );
1998 if( res != S_OK )
1999 return res;
2001 if( V_VT(pvargSrc) & VT_BYREF )
2003 VARIANTARG varg;
2004 VariantInit( &varg );
2006 /* handle the in place copy.
2008 if( pvargDest == pvargSrc )
2010 /* we will use a copy of the source instead.
2012 res = VariantCopy( &varg, pvargSrc );
2013 pvargSrc = &varg;
2016 if( res == S_OK )
2018 res = VariantClear( pvargDest );
2020 if( res == S_OK )
2023 * The VT_ARRAY flag is another way to designate a safearray variant.
2025 if ( V_VT(pvargSrc) & VT_ARRAY)
2027 SafeArrayCopy(*V_UNION(pvargSrc,pparray), &V_UNION(pvargDest,parray));
2029 else
2031 /* In the case of by reference we need
2032 * to copy the date pointed to by the variant.
2035 /* Get the variant type.
2037 switch( V_VT(pvargSrc) & VT_TYPEMASK )
2039 case( VT_BSTR ):
2040 V_UNION(pvargDest,bstrVal) = SYSDUPSTRING( *(V_UNION(pvargSrc,pbstrVal)) );
2041 break;
2042 case( VT_DISPATCH ):
2043 break;
2044 case( VT_VARIANT ):
2046 /* Prevent from cycling. According to tests on
2047 * VariantCopyInd in Windows and the documentation
2048 * this API dereferences the inner Variants to only one depth.
2049 * If the inner Variant itself contains an
2050 * other inner variant the E_INVALIDARG error is
2051 * returned.
2053 if( pvargSrc->n1.n2.wReserved1 & PROCESSING_INNER_VARIANT )
2055 /* If we get here we are attempting to deference
2056 * an inner variant that that is itself contained
2057 * in an inner variant so report E_INVALIDARG error.
2059 res = E_INVALIDARG;
2061 else
2063 /* Set the processing inner variant flag.
2064 * We will set this flag in the inner variant
2065 * that will be passed to the VariantCopyInd function.
2067 (V_UNION(pvargSrc,pvarVal))->n1.n2.wReserved1 |= PROCESSING_INNER_VARIANT;
2069 /* Dereference the inner variant.
2071 res = VariantCopyInd( pvargDest, V_UNION(pvargSrc,pvarVal) );
2072 /* We must also copy its type, I think.
2074 V_VT(pvargSrc) = V_VT(V_UNION(pvargSrc,pvarVal));
2077 break;
2078 case( VT_UNKNOWN ):
2079 break;
2080 case( VT_SAFEARRAY ):
2081 SafeArrayCopy(*V_UNION(pvargSrc,pparray), &V_UNION(pvargDest,parray));
2082 break;
2083 default:
2084 /* This is a by reference Variant which means that the union
2085 * part of the Variant contains a pointer to some data of
2086 * type "V_VT(pvargSrc) & VT_TYPEMASK".
2087 * We will deference this data in a generic fashion using
2088 * the void pointer "Variant.u.byref".
2089 * We will copy this data into the union of the destination
2090 * Variant.
2092 memcpy( &pvargDest->n1.n2.n3, V_UNION(pvargSrc,byref), SizeOfVariantData( pvargSrc ) );
2093 break;
2097 if (res == S_OK) V_VT(pvargDest) = V_VT(pvargSrc) & VT_TYPEMASK;
2101 /* this should not fail.
2103 VariantClear( &varg );
2105 else
2107 res = VariantCopy( pvargDest, pvargSrc );
2110 return res;
2113 /******************************************************************************
2114 * VariantChangeType [OLEAUT32.12]
2116 HRESULT WINAPI VariantChangeType(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
2117 USHORT wFlags, VARTYPE vt)
2119 return VariantChangeTypeEx( pvargDest, pvargSrc, 0, wFlags, vt );
2122 /******************************************************************************
2123 * VariantChangeTypeEx [OLEAUT32.147]
2125 HRESULT WINAPI VariantChangeTypeEx(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
2126 LCID lcid, USHORT wFlags, VARTYPE vt)
2128 HRESULT res = S_OK;
2129 VARIANTARG varg;
2130 VariantInit( &varg );
2132 TRACE("(%p, %p, %ld, %u, %u) vt=%d\n", pvargDest, pvargSrc, lcid, wFlags, vt, V_VT(pvargSrc));
2133 TRACE("Src Var:\n");
2134 dump_Variant(pvargSrc);
2136 /* validate our source argument.
2138 res = ValidateVariantType( V_VT(pvargSrc) );
2140 /* validate the vartype.
2142 if( res == S_OK )
2144 res = ValidateVt( vt );
2147 /* if we are doing an in-place conversion make a copy of the source.
2149 if( res == S_OK && pvargDest == pvargSrc )
2151 res = VariantCopy( &varg, pvargSrc );
2152 pvargSrc = &varg;
2155 if( res == S_OK )
2157 /* free up the destination variant.
2159 res = VariantClear( pvargDest );
2162 if( res == S_OK )
2164 if( V_VT(pvargSrc) & VT_BYREF )
2166 /* Convert the source variant to a "byvalue" variant.
2168 VARIANTARG Variant;
2169 VariantInit( &Variant );
2170 res = VariantCopyInd( &Variant, pvargSrc );
2171 if( res == S_OK )
2173 res = Coerce( pvargDest, lcid, wFlags, &Variant, vt );
2174 /* this should not fail.
2176 VariantClear( &Variant );
2180 else
2182 /* Use the current "byvalue" source variant.
2184 res = Coerce( pvargDest, lcid, wFlags, pvargSrc, vt );
2187 /* this should not fail.
2189 VariantClear( &varg );
2191 /* set the type of the destination
2193 if ( res == S_OK )
2194 V_VT(pvargDest) = vt;
2196 TRACE("Dest Var:\n");
2197 dump_Variant(pvargDest);
2199 return res;
2205 /******************************************************************************
2206 * VarUI1FromI2 [OLEAUT32.130]
2208 HRESULT WINAPI VarUI1FromI2(short sIn, BYTE* pbOut)
2210 TRACE("( %d, %p ), stub\n", sIn, pbOut );
2212 /* Check range of value.
2214 if( sIn < UI1_MIN || sIn > UI1_MAX )
2216 return DISP_E_OVERFLOW;
2219 *pbOut = (BYTE) sIn;
2221 return S_OK;
2224 /******************************************************************************
2225 * VarUI1FromI4 [OLEAUT32.131]
2227 HRESULT WINAPI VarUI1FromI4(LONG lIn, BYTE* pbOut)
2229 TRACE("( %ld, %p ), stub\n", lIn, pbOut );
2231 /* Check range of value.
2233 if( lIn < UI1_MIN || lIn > UI1_MAX )
2235 return DISP_E_OVERFLOW;
2238 *pbOut = (BYTE) lIn;
2240 return S_OK;
2244 /******************************************************************************
2245 * VarUI1FromR4 [OLEAUT32.132]
2247 HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut)
2249 TRACE("( %f, %p ), stub\n", fltIn, pbOut );
2251 /* Check range of value.
2253 fltIn = round( fltIn );
2254 if( fltIn < UI1_MIN || fltIn > UI1_MAX )
2256 return DISP_E_OVERFLOW;
2259 *pbOut = (BYTE) fltIn;
2261 return S_OK;
2264 /******************************************************************************
2265 * VarUI1FromR8 [OLEAUT32.133]
2267 HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut)
2269 TRACE("( %f, %p ), stub\n", dblIn, pbOut );
2271 /* Check range of value.
2273 dblIn = round( dblIn );
2274 if( dblIn < UI1_MIN || dblIn > UI1_MAX )
2276 return DISP_E_OVERFLOW;
2279 *pbOut = (BYTE) dblIn;
2281 return S_OK;
2284 /******************************************************************************
2285 * VarUI1FromDate [OLEAUT32.135]
2287 HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut)
2289 TRACE("( %f, %p ), stub\n", dateIn, pbOut );
2291 /* Check range of value.
2293 dateIn = round( dateIn );
2294 if( dateIn < UI1_MIN || dateIn > UI1_MAX )
2296 return DISP_E_OVERFLOW;
2299 *pbOut = (BYTE) dateIn;
2301 return S_OK;
2304 /******************************************************************************
2305 * VarUI1FromBool [OLEAUT32.138]
2307 HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut)
2309 TRACE("( %d, %p ), stub\n", boolIn, pbOut );
2311 *pbOut = (BYTE) boolIn;
2313 return S_OK;
2316 /******************************************************************************
2317 * VarUI1FromI1 [OLEAUT32.237]
2319 HRESULT WINAPI VarUI1FromI1(CHAR cIn, BYTE* pbOut)
2321 TRACE("( %c, %p ), stub\n", cIn, pbOut );
2323 *pbOut = cIn;
2325 return S_OK;
2328 /******************************************************************************
2329 * VarUI1FromUI2 [OLEAUT32.238]
2331 HRESULT WINAPI VarUI1FromUI2(USHORT uiIn, BYTE* pbOut)
2333 TRACE("( %d, %p ), stub\n", uiIn, pbOut );
2335 /* Check range of value.
2337 if( uiIn > UI1_MAX )
2339 return DISP_E_OVERFLOW;
2342 *pbOut = (BYTE) uiIn;
2344 return S_OK;
2347 /******************************************************************************
2348 * VarUI1FromUI4 [OLEAUT32.239]
2350 HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut)
2352 TRACE("( %ld, %p ), stub\n", ulIn, pbOut );
2354 /* Check range of value.
2356 if( ulIn > UI1_MAX )
2358 return DISP_E_OVERFLOW;
2361 *pbOut = (BYTE) ulIn;
2363 return S_OK;
2367 /******************************************************************************
2368 * VarUI1FromStr [OLEAUT32.136]
2370 HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut)
2372 double dValue = 0.0;
2373 LPSTR pNewString = NULL;
2375 TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, pbOut );
2377 /* Check if we have a valid argument
2379 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2380 RemoveCharacterFromString( pNewString, "," );
2381 if( IsValidRealString( pNewString ) == FALSE )
2383 return DISP_E_TYPEMISMATCH;
2386 /* Convert the valid string to a floating point number.
2388 dValue = atof( pNewString );
2390 /* We don't need the string anymore so free it.
2392 HeapFree( GetProcessHeap(), 0 , pNewString );
2394 /* Check range of value.
2396 dValue = round( dValue );
2397 if( dValue < UI1_MIN || dValue > UI1_MAX )
2399 return DISP_E_OVERFLOW;
2402 *pbOut = (BYTE) dValue;
2404 return S_OK;
2407 /**********************************************************************
2408 * VarUI1FromCy [OLEAUT32.134]
2409 * Convert currency to unsigned char
2411 HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut) {
2412 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2414 if (t > UI1_MAX || t < UI1_MIN) return DISP_E_OVERFLOW;
2416 *pbOut = (BYTE)t;
2417 return S_OK;
2420 /******************************************************************************
2421 * VarI2FromUI1 [OLEAUT32.48]
2423 HRESULT WINAPI VarI2FromUI1(BYTE bIn, short* psOut)
2425 TRACE("( 0x%08x, %p ), stub\n", bIn, psOut );
2427 *psOut = (short) bIn;
2429 return S_OK;
2432 /******************************************************************************
2433 * VarI2FromI4 [OLEAUT32.49]
2435 HRESULT WINAPI VarI2FromI4(LONG lIn, short* psOut)
2437 TRACE("( %lx, %p ), stub\n", lIn, psOut );
2439 /* Check range of value.
2441 if( lIn < I2_MIN || lIn > I2_MAX )
2443 return DISP_E_OVERFLOW;
2446 *psOut = (short) lIn;
2448 return S_OK;
2451 /******************************************************************************
2452 * VarI2FromR4 [OLEAUT32.50]
2454 HRESULT WINAPI VarI2FromR4(FLOAT fltIn, short* psOut)
2456 TRACE("( %f, %p ), stub\n", fltIn, psOut );
2458 /* Check range of value.
2460 fltIn = round( fltIn );
2461 if( fltIn < I2_MIN || fltIn > I2_MAX )
2463 return DISP_E_OVERFLOW;
2466 *psOut = (short) fltIn;
2468 return S_OK;
2471 /******************************************************************************
2472 * VarI2FromR8 [OLEAUT32.51]
2474 HRESULT WINAPI VarI2FromR8(double dblIn, short* psOut)
2476 TRACE("( %f, %p ), stub\n", dblIn, psOut );
2478 /* Check range of value.
2480 dblIn = round( dblIn );
2481 if( dblIn < I2_MIN || dblIn > I2_MAX )
2483 return DISP_E_OVERFLOW;
2486 *psOut = (short) dblIn;
2488 return S_OK;
2491 /******************************************************************************
2492 * VarI2FromDate [OLEAUT32.53]
2494 HRESULT WINAPI VarI2FromDate(DATE dateIn, short* psOut)
2496 TRACE("( %f, %p ), stub\n", dateIn, psOut );
2498 /* Check range of value.
2500 dateIn = round( dateIn );
2501 if( dateIn < I2_MIN || dateIn > I2_MAX )
2503 return DISP_E_OVERFLOW;
2506 *psOut = (short) dateIn;
2508 return S_OK;
2511 /******************************************************************************
2512 * VarI2FromBool [OLEAUT32.56]
2514 HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, short* psOut)
2516 TRACE("( %d, %p ), stub\n", boolIn, psOut );
2518 *psOut = (short) boolIn;
2520 return S_OK;
2523 /******************************************************************************
2524 * VarI2FromI1 [OLEAUT32.205]
2526 HRESULT WINAPI VarI2FromI1(CHAR cIn, short* psOut)
2528 TRACE("( %c, %p ), stub\n", cIn, psOut );
2530 *psOut = (short) cIn;
2532 return S_OK;
2535 /******************************************************************************
2536 * VarI2FromUI2 [OLEAUT32.206]
2538 HRESULT WINAPI VarI2FromUI2(USHORT uiIn, short* psOut)
2540 TRACE("( %d, %p ), stub\n", uiIn, psOut );
2542 /* Check range of value.
2544 if( uiIn > I2_MAX )
2546 return DISP_E_OVERFLOW;
2549 *psOut = (short) uiIn;
2551 return S_OK;
2554 /******************************************************************************
2555 * VarI2FromUI4 [OLEAUT32.207]
2557 HRESULT WINAPI VarI2FromUI4(ULONG ulIn, short* psOut)
2559 TRACE("( %lx, %p ), stub\n", ulIn, psOut );
2561 /* Check range of value.
2563 if( ulIn < I2_MIN || ulIn > I2_MAX )
2565 return DISP_E_OVERFLOW;
2568 *psOut = (short) ulIn;
2570 return S_OK;
2573 /******************************************************************************
2574 * VarI2FromStr [OLEAUT32.54]
2576 HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, short* psOut)
2578 double dValue = 0.0;
2579 LPSTR pNewString = NULL;
2581 TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, psOut );
2583 /* Check if we have a valid argument
2585 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2586 RemoveCharacterFromString( pNewString, "," );
2587 if( IsValidRealString( pNewString ) == FALSE )
2589 return DISP_E_TYPEMISMATCH;
2592 /* Convert the valid string to a floating point number.
2594 dValue = atof( pNewString );
2596 /* We don't need the string anymore so free it.
2598 HeapFree( GetProcessHeap(), 0, pNewString );
2600 /* Check range of value.
2602 dValue = round( dValue );
2603 if( dValue < I2_MIN || dValue > I2_MAX )
2605 return DISP_E_OVERFLOW;
2608 *psOut = (short) dValue;
2610 return S_OK;
2613 /**********************************************************************
2614 * VarI2FromCy [OLEAUT32.52]
2615 * Convert currency to signed short
2617 HRESULT WINAPI VarI2FromCy(CY cyIn, short* psOut) {
2618 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2620 if (t > I2_MAX || t < I2_MIN) return DISP_E_OVERFLOW;
2622 *psOut = (SHORT)t;
2623 return S_OK;
2626 /******************************************************************************
2627 * VarI4FromUI1 [OLEAUT32.58]
2629 HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG* plOut)
2631 TRACE("( %X, %p ), stub\n", bIn, plOut );
2633 *plOut = (LONG) bIn;
2635 return S_OK;
2639 /******************************************************************************
2640 * VarI4FromR4 [OLEAUT32.60]
2642 HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG* plOut)
2644 TRACE("( %f, %p ), stub\n", fltIn, plOut );
2646 /* Check range of value.
2648 fltIn = round( fltIn );
2649 if( fltIn < I4_MIN || fltIn > I4_MAX )
2651 return DISP_E_OVERFLOW;
2654 *plOut = (LONG) fltIn;
2656 return S_OK;
2659 /******************************************************************************
2660 * VarI4FromR8 [OLEAUT32.61]
2662 HRESULT WINAPI VarI4FromR8(double dblIn, LONG* plOut)
2664 TRACE("( %f, %p ), stub\n", dblIn, plOut );
2666 /* Check range of value.
2668 dblIn = round( dblIn );
2669 if( dblIn < I4_MIN || dblIn > I4_MAX )
2671 return DISP_E_OVERFLOW;
2674 *plOut = (LONG) dblIn;
2676 return S_OK;
2679 /******************************************************************************
2680 * VarI4FromDate [OLEAUT32.63]
2682 HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG* plOut)
2684 TRACE("( %f, %p ), stub\n", dateIn, plOut );
2686 /* Check range of value.
2688 dateIn = round( dateIn );
2689 if( dateIn < I4_MIN || dateIn > I4_MAX )
2691 return DISP_E_OVERFLOW;
2694 *plOut = (LONG) dateIn;
2696 return S_OK;
2699 /******************************************************************************
2700 * VarI4FromBool [OLEAUT32.66]
2702 HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG* plOut)
2704 TRACE("( %d, %p ), stub\n", boolIn, plOut );
2706 *plOut = (LONG) boolIn;
2708 return S_OK;
2711 /******************************************************************************
2712 * VarI4FromI1 [OLEAUT32.209]
2714 HRESULT WINAPI VarI4FromI1(CHAR cIn, LONG* plOut)
2716 TRACE("( %c, %p ), stub\n", cIn, plOut );
2718 *plOut = (LONG) cIn;
2720 return S_OK;
2723 /******************************************************************************
2724 * VarI4FromUI2 [OLEAUT32.210]
2726 HRESULT WINAPI VarI4FromUI2(USHORT uiIn, LONG* plOut)
2728 TRACE("( %d, %p ), stub\n", uiIn, plOut );
2730 *plOut = (LONG) uiIn;
2732 return S_OK;
2735 /******************************************************************************
2736 * VarI4FromUI4 [OLEAUT32.211]
2738 HRESULT WINAPI VarI4FromUI4(ULONG ulIn, LONG* plOut)
2740 TRACE("( %lx, %p ), stub\n", ulIn, plOut );
2742 /* Check range of value.
2744 if( ulIn < I4_MIN || ulIn > I4_MAX )
2746 return DISP_E_OVERFLOW;
2749 *plOut = (LONG) ulIn;
2751 return S_OK;
2754 /******************************************************************************
2755 * VarI4FromI2 [OLEAUT32.59]
2757 HRESULT WINAPI VarI4FromI2(short sIn, LONG* plOut)
2759 TRACE("( %d, %p ), stub\n", sIn, plOut );
2761 *plOut = (LONG) sIn;
2763 return S_OK;
2766 /******************************************************************************
2767 * VarI4FromStr [OLEAUT32.64]
2769 HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG* plOut)
2771 double dValue = 0.0;
2772 LPSTR pNewString = NULL;
2774 TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, plOut );
2776 /* Check if we have a valid argument
2778 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2779 RemoveCharacterFromString( pNewString, "," );
2780 if( IsValidRealString( pNewString ) == FALSE )
2782 return DISP_E_TYPEMISMATCH;
2785 /* Convert the valid string to a floating point number.
2787 dValue = atof( pNewString );
2789 /* We don't need the string anymore so free it.
2791 HeapFree( GetProcessHeap(), 0, pNewString );
2793 /* Check range of value.
2795 dValue = round( dValue );
2796 if( dValue < I4_MIN || dValue > I4_MAX )
2798 return DISP_E_OVERFLOW;
2801 *plOut = (LONG) dValue;
2803 return S_OK;
2806 /**********************************************************************
2807 * VarI4FromCy [OLEAUT32.62]
2808 * Convert currency to signed long
2810 HRESULT WINAPI VarI4FromCy(CY cyIn, LONG* plOut) {
2811 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2813 if (t > I4_MAX || t < I4_MIN) return DISP_E_OVERFLOW;
2815 *plOut = (LONG)t;
2816 return S_OK;
2819 /******************************************************************************
2820 * VarR4FromUI1 [OLEAUT32.68]
2822 HRESULT WINAPI VarR4FromUI1(BYTE bIn, FLOAT* pfltOut)
2824 TRACE("( %X, %p ), stub\n", bIn, pfltOut );
2826 *pfltOut = (FLOAT) bIn;
2828 return S_OK;
2831 /******************************************************************************
2832 * VarR4FromI2 [OLEAUT32.69]
2834 HRESULT WINAPI VarR4FromI2(short sIn, FLOAT* pfltOut)
2836 TRACE("( %d, %p ), stub\n", sIn, pfltOut );
2838 *pfltOut = (FLOAT) sIn;
2840 return S_OK;
2843 /******************************************************************************
2844 * VarR4FromI4 [OLEAUT32.70]
2846 HRESULT WINAPI VarR4FromI4(LONG lIn, FLOAT* pfltOut)
2848 TRACE("( %lx, %p ), stub\n", lIn, pfltOut );
2850 *pfltOut = (FLOAT) lIn;
2852 return S_OK;
2855 /******************************************************************************
2856 * VarR4FromR8 [OLEAUT32.71]
2858 HRESULT WINAPI VarR4FromR8(double dblIn, FLOAT* pfltOut)
2860 TRACE("( %f, %p ), stub\n", dblIn, pfltOut );
2862 /* Check range of value.
2864 if( dblIn < -(FLT_MAX) || dblIn > FLT_MAX )
2866 return DISP_E_OVERFLOW;
2869 *pfltOut = (FLOAT) dblIn;
2871 return S_OK;
2874 /******************************************************************************
2875 * VarR4FromDate [OLEAUT32.73]
2877 HRESULT WINAPI VarR4FromDate(DATE dateIn, FLOAT* pfltOut)
2879 TRACE("( %f, %p ), stub\n", dateIn, pfltOut );
2881 /* Check range of value.
2883 if( dateIn < -(FLT_MAX) || dateIn > FLT_MAX )
2885 return DISP_E_OVERFLOW;
2888 *pfltOut = (FLOAT) dateIn;
2890 return S_OK;
2893 /******************************************************************************
2894 * VarR4FromBool [OLEAUT32.76]
2896 HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, FLOAT* pfltOut)
2898 TRACE("( %d, %p ), stub\n", boolIn, pfltOut );
2900 *pfltOut = (FLOAT) boolIn;
2902 return S_OK;
2905 /******************************************************************************
2906 * VarR4FromI1 [OLEAUT32.213]
2908 HRESULT WINAPI VarR4FromI1(CHAR cIn, FLOAT* pfltOut)
2910 TRACE("( %c, %p ), stub\n", cIn, pfltOut );
2912 *pfltOut = (FLOAT) cIn;
2914 return S_OK;
2917 /******************************************************************************
2918 * VarR4FromUI2 [OLEAUT32.214]
2920 HRESULT WINAPI VarR4FromUI2(USHORT uiIn, FLOAT* pfltOut)
2922 TRACE("( %d, %p ), stub\n", uiIn, pfltOut );
2924 *pfltOut = (FLOAT) uiIn;
2926 return S_OK;
2929 /******************************************************************************
2930 * VarR4FromUI4 [OLEAUT32.215]
2932 HRESULT WINAPI VarR4FromUI4(ULONG ulIn, FLOAT* pfltOut)
2934 TRACE("( %ld, %p ), stub\n", ulIn, pfltOut );
2936 *pfltOut = (FLOAT) ulIn;
2938 return S_OK;
2941 /******************************************************************************
2942 * VarR4FromStr [OLEAUT32.74]
2944 HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, FLOAT* pfltOut)
2946 double dValue = 0.0;
2947 LPSTR pNewString = NULL;
2949 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pfltOut );
2951 /* Check if we have a valid argument
2953 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2954 RemoveCharacterFromString( pNewString, "," );
2955 if( IsValidRealString( pNewString ) == FALSE )
2957 return DISP_E_TYPEMISMATCH;
2960 /* Convert the valid string to a floating point number.
2962 dValue = atof( pNewString );
2964 /* We don't need the string anymore so free it.
2966 HeapFree( GetProcessHeap(), 0, pNewString );
2968 /* Check range of value.
2970 if( dValue < -(FLT_MAX) || dValue > FLT_MAX )
2972 return DISP_E_OVERFLOW;
2975 *pfltOut = (FLOAT) dValue;
2977 return S_OK;
2980 /**********************************************************************
2981 * VarR4FromCy [OLEAUT32.72]
2982 * Convert currency to float
2984 HRESULT WINAPI VarR4FromCy(CY cyIn, FLOAT* pfltOut) {
2985 *pfltOut = (FLOAT)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2987 return S_OK;
2990 /******************************************************************************
2991 * VarR8FromUI1 [OLEAUT32.78]
2993 HRESULT WINAPI VarR8FromUI1(BYTE bIn, double* pdblOut)
2995 TRACE("( %d, %p ), stub\n", bIn, pdblOut );
2997 *pdblOut = (double) bIn;
2999 return S_OK;
3002 /******************************************************************************
3003 * VarR8FromI2 [OLEAUT32.79]
3005 HRESULT WINAPI VarR8FromI2(short sIn, double* pdblOut)
3007 TRACE("( %d, %p ), stub\n", sIn, pdblOut );
3009 *pdblOut = (double) sIn;
3011 return S_OK;
3014 /******************************************************************************
3015 * VarR8FromI4 [OLEAUT32.80]
3017 HRESULT WINAPI VarR8FromI4(LONG lIn, double* pdblOut)
3019 TRACE("( %ld, %p ), stub\n", lIn, pdblOut );
3021 *pdblOut = (double) lIn;
3023 return S_OK;
3026 /******************************************************************************
3027 * VarR8FromR4 [OLEAUT32.81]
3029 HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double* pdblOut)
3031 TRACE("( %f, %p ), stub\n", fltIn, pdblOut );
3033 *pdblOut = (double) fltIn;
3035 return S_OK;
3038 /******************************************************************************
3039 * VarR8FromDate [OLEAUT32.83]
3041 HRESULT WINAPI VarR8FromDate(DATE dateIn, double* pdblOut)
3043 TRACE("( %f, %p ), stub\n", dateIn, pdblOut );
3045 *pdblOut = (double) dateIn;
3047 return S_OK;
3050 /******************************************************************************
3051 * VarR8FromBool [OLEAUT32.86]
3053 HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double* pdblOut)
3055 TRACE("( %d, %p ), stub\n", boolIn, pdblOut );
3057 *pdblOut = (double) boolIn;
3059 return S_OK;
3062 /******************************************************************************
3063 * VarR8FromI1 [OLEAUT32.217]
3065 HRESULT WINAPI VarR8FromI1(CHAR cIn, double* pdblOut)
3067 TRACE("( %c, %p ), stub\n", cIn, pdblOut );
3069 *pdblOut = (double) cIn;
3071 return S_OK;
3074 /******************************************************************************
3075 * VarR8FromUI2 [OLEAUT32.218]
3077 HRESULT WINAPI VarR8FromUI2(USHORT uiIn, double* pdblOut)
3079 TRACE("( %d, %p ), stub\n", uiIn, pdblOut );
3081 *pdblOut = (double) uiIn;
3083 return S_OK;
3086 /******************************************************************************
3087 * VarR8FromUI4 [OLEAUT32.219]
3089 HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double* pdblOut)
3091 TRACE("( %ld, %p ), stub\n", ulIn, pdblOut );
3093 *pdblOut = (double) ulIn;
3095 return S_OK;
3098 /******************************************************************************
3099 * VarR8FromStr [OLEAUT32.84]
3101 HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double* pdblOut)
3103 double dValue = 0.0;
3104 LPSTR pNewString = NULL;
3106 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3107 TRACE("( %s, %ld, %ld, %p ), stub\n", pNewString, lcid, dwFlags, pdblOut );
3109 /* Check if we have a valid argument
3111 RemoveCharacterFromString( pNewString, "," );
3112 if( IsValidRealString( pNewString ) == FALSE )
3114 return DISP_E_TYPEMISMATCH;
3117 /* Convert the valid string to a floating point number.
3119 dValue = atof( pNewString );
3121 /* We don't need the string anymore so free it.
3123 HeapFree( GetProcessHeap(), 0, pNewString );
3125 *pdblOut = dValue;
3127 return S_OK;
3130 /**********************************************************************
3131 * VarR8FromCy [OLEAUT32.82]
3132 * Convert currency to double
3134 HRESULT WINAPI VarR8FromCy(CY cyIn, double* pdblOut) {
3135 *pdblOut = (double)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3136 TRACE("%lu %ld -> %f\n", cyIn.s.Hi, cyIn.s.Lo, *pdblOut);
3137 return S_OK;
3140 /******************************************************************************
3141 * VarDateFromUI1 [OLEAUT32.88]
3143 HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
3145 TRACE("( %d, %p ), stub\n", bIn, pdateOut );
3147 *pdateOut = (DATE) bIn;
3149 return S_OK;
3152 /******************************************************************************
3153 * VarDateFromI2 [OLEAUT32.89]
3155 HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
3157 TRACE("( %d, %p ), stub\n", sIn, pdateOut );
3159 *pdateOut = (DATE) sIn;
3161 return S_OK;
3164 /******************************************************************************
3165 * VarDateFromI4 [OLEAUT32.90]
3167 HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
3169 TRACE("( %ld, %p ), stub\n", lIn, pdateOut );
3171 if( lIn < DATE_MIN || lIn > DATE_MAX )
3173 return DISP_E_OVERFLOW;
3176 *pdateOut = (DATE) lIn;
3178 return S_OK;
3181 /******************************************************************************
3182 * VarDateFromR4 [OLEAUT32.91]
3184 HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
3186 TRACE("( %f, %p ), stub\n", fltIn, pdateOut );
3188 if( ceil(fltIn) < DATE_MIN || floor(fltIn) > DATE_MAX )
3190 return DISP_E_OVERFLOW;
3193 *pdateOut = (DATE) fltIn;
3195 return S_OK;
3198 /******************************************************************************
3199 * VarDateFromR8 [OLEAUT32.92]
3201 HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
3203 TRACE("( %f, %p ), stub\n", dblIn, pdateOut );
3205 if( ceil(dblIn) < DATE_MIN || floor(dblIn) > DATE_MAX )
3207 return DISP_E_OVERFLOW;
3210 *pdateOut = (DATE) dblIn;
3212 return S_OK;
3215 /******************************************************************************
3216 * VarDateFromStr [OLEAUT32.94]
3217 * The string representing the date is composed of two parts, a date and time.
3219 * The format of the time is has follows:
3220 * hh[:mm][:ss][AM|PM]
3221 * Whitespace can be inserted anywhere between these tokens. A whitespace consists
3222 * of space and/or tab characters, which are ignored.
3224 * The formats for the date part are has follows:
3225 * mm/[dd/][yy]yy
3226 * [dd/]mm/[yy]yy
3227 * [yy]yy/mm/dd
3228 * January dd[,] [yy]yy
3229 * dd January [yy]yy
3230 * [yy]yy January dd
3231 * Whitespace can be inserted anywhere between these tokens.
3233 * The formats for the date and time string are has follows.
3234 * date[whitespace][time]
3235 * [time][whitespace]date
3237 * These are the only characters allowed in a string representing a date and time:
3238 * [A-Z] [a-z] [0-9] ':' '-' '/' ',' ' ' '\t'
3240 HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
3242 HRESULT ret = S_OK;
3243 struct tm TM;
3245 memset( &TM, 0, sizeof(TM) );
3247 TRACE("( %p, %lx, %lx, %p ), stub\n", strIn, lcid, dwFlags, pdateOut );
3249 if( DateTimeStringToTm( strIn, dwFlags, &TM ) )
3251 if( TmToDATE( &TM, pdateOut ) == FALSE )
3253 ret = E_INVALIDARG;
3256 else
3258 ret = DISP_E_TYPEMISMATCH;
3260 TRACE("Return value %f\n", *pdateOut);
3261 return ret;
3264 /******************************************************************************
3265 * VarDateFromI1 [OLEAUT32.221]
3267 HRESULT WINAPI VarDateFromI1(CHAR cIn, DATE* pdateOut)
3269 TRACE("( %c, %p ), stub\n", cIn, pdateOut );
3271 *pdateOut = (DATE) cIn;
3273 return S_OK;
3276 /******************************************************************************
3277 * VarDateFromUI2 [OLEAUT32.222]
3279 HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
3281 TRACE("( %d, %p ), stub\n", uiIn, pdateOut );
3283 if( uiIn > DATE_MAX )
3285 return DISP_E_OVERFLOW;
3288 *pdateOut = (DATE) uiIn;
3290 return S_OK;
3293 /******************************************************************************
3294 * VarDateFromUI4 [OLEAUT32.223]
3296 HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
3298 TRACE("( %ld, %p ), stub\n", ulIn, pdateOut );
3300 if( ulIn < DATE_MIN || ulIn > DATE_MAX )
3302 return DISP_E_OVERFLOW;
3305 *pdateOut = (DATE) ulIn;
3307 return S_OK;
3310 /******************************************************************************
3311 * VarDateFromBool [OLEAUT32.96]
3313 HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
3315 TRACE("( %d, %p ), stub\n", boolIn, pdateOut );
3317 *pdateOut = (DATE) boolIn;
3319 return S_OK;
3322 /**********************************************************************
3323 * VarDateFromCy [OLEAUT32.93]
3324 * Convert currency to date
3326 HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut) {
3327 *pdateOut = (DATE)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3329 if (*pdateOut > DATE_MAX || *pdateOut < DATE_MIN) return DISP_E_TYPEMISMATCH;
3330 return S_OK;
3333 /******************************************************************************
3334 * VarBstrFromUI1 [OLEAUT32.108]
3336 HRESULT WINAPI VarBstrFromUI1(BYTE bVal, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3338 TRACE("( %d, %ld, %ld, %p ), stub\n", bVal, lcid, dwFlags, pbstrOut );
3339 sprintf( pBuffer, "%d", bVal );
3341 *pbstrOut = StringDupAtoBstr( pBuffer );
3343 return S_OK;
3346 /******************************************************************************
3347 * VarBstrFromI2 [OLEAUT32.109]
3349 HRESULT WINAPI VarBstrFromI2(short iVal, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3351 TRACE("( %d, %ld, %ld, %p ), stub\n", iVal, lcid, dwFlags, pbstrOut );
3352 sprintf( pBuffer, "%d", iVal );
3353 *pbstrOut = StringDupAtoBstr( pBuffer );
3355 return S_OK;
3358 /******************************************************************************
3359 * VarBstrFromI4 [OLEAUT32.110]
3361 HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3363 TRACE("( %ld, %ld, %ld, %p ), stub\n", lIn, lcid, dwFlags, pbstrOut );
3365 sprintf( pBuffer, "%ld", lIn );
3366 *pbstrOut = StringDupAtoBstr( pBuffer );
3368 return S_OK;
3371 /******************************************************************************
3372 * VarBstrFromR4 [OLEAUT32.111]
3374 HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3376 TRACE("( %f, %ld, %ld, %p ), stub\n", fltIn, lcid, dwFlags, pbstrOut );
3378 sprintf( pBuffer, "%.7g", fltIn );
3379 *pbstrOut = StringDupAtoBstr( pBuffer );
3381 return S_OK;
3384 /******************************************************************************
3385 * VarBstrFromR8 [OLEAUT32.112]
3387 HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3389 TRACE("( %f, %ld, %ld, %p ), stub\n", dblIn, lcid, dwFlags, pbstrOut );
3391 sprintf( pBuffer, "%.15g", dblIn );
3392 *pbstrOut = StringDupAtoBstr( pBuffer );
3394 return S_OK;
3397 /******************************************************************************
3398 * VarBstrFromCy [OLEAUT32.113]
3400 HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut) {
3401 HRESULT rc = S_OK;
3402 double curVal = 0.0;
3404 TRACE("([cyIn], %08lx, %08lx, %p), partial stub (no flags handled).\n", lcid, dwFlags, pbstrOut);
3406 /* Firstly get the currency in a double, then put it in a buffer */
3407 rc = VarR8FromCy(cyIn, &curVal);
3408 if (rc == S_OK) {
3409 sprintf(pBuffer, "%g", curVal);
3410 *pbstrOut = StringDupAtoBstr( pBuffer );
3412 return rc;
3416 /******************************************************************************
3417 * VarBstrFromDate [OLEAUT32.114]
3419 * The date is implemented using an 8 byte floating-point number.
3420 * Days are represented by whole numbers increments starting with 0.00 as
3421 * being December 30 1899, midnight.
3422 * The hours are expressed as the fractional part of the number.
3423 * December 30 1899 at midnight = 0.00
3424 * January 1 1900 at midnight = 2.00
3425 * January 4 1900 at 6 AM = 5.25
3426 * January 4 1900 at noon = 5.50
3427 * December 29 1899 at midnight = -1.00
3428 * December 18 1899 at midnight = -12.00
3429 * December 18 1899 at 6AM = -12.25
3430 * December 18 1899 at 6PM = -12.75
3431 * December 19 1899 at midnight = -11.00
3432 * The tm structure is as follows:
3433 * struct tm {
3434 * int tm_sec; seconds after the minute - [0,59]
3435 * int tm_min; minutes after the hour - [0,59]
3436 * int tm_hour; hours since midnight - [0,23]
3437 * int tm_mday; day of the month - [1,31]
3438 * int tm_mon; months since January - [0,11]
3439 * int tm_year; years
3440 * int tm_wday; days since Sunday - [0,6]
3441 * int tm_yday; days since January 1 - [0,365]
3442 * int tm_isdst; daylight savings time flag
3443 * };
3445 HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3447 struct tm TM;
3448 memset( &TM, 0, sizeof(TM) );
3450 TRACE("( %20.20f, %ld, %ld, %p ), stub\n", dateIn, lcid, dwFlags, pbstrOut );
3452 if( DateToTm( dateIn, dwFlags, &TM ) == FALSE )
3454 return E_INVALIDARG;
3457 if( dwFlags & VAR_DATEVALUEONLY )
3458 strftime( pBuffer, BUFFER_MAX, "%x", &TM );
3459 else if( dwFlags & VAR_TIMEVALUEONLY )
3460 strftime( pBuffer, BUFFER_MAX, "%X", &TM );
3461 else
3462 strftime( pBuffer, BUFFER_MAX, "%x %X", &TM );
3464 TRACE("result: %s\n", pBuffer);
3465 *pbstrOut = StringDupAtoBstr( pBuffer );
3466 return S_OK;
3469 /******************************************************************************
3470 * VarBstrFromBool [OLEAUT32.116]
3472 HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3474 TRACE("( %d, %ld, %ld, %p ), stub\n", boolIn, lcid, dwFlags, pbstrOut );
3476 sprintf( pBuffer, (boolIn == VARIANT_FALSE) ? "False" : "True" );
3478 *pbstrOut = StringDupAtoBstr( pBuffer );
3480 return S_OK;
3483 /******************************************************************************
3484 * VarBstrFromI1 [OLEAUT32.229]
3486 HRESULT WINAPI VarBstrFromI1(CHAR cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3488 TRACE("( %c, %ld, %ld, %p ), stub\n", cIn, lcid, dwFlags, pbstrOut );
3489 sprintf( pBuffer, "%d", cIn );
3490 *pbstrOut = StringDupAtoBstr( pBuffer );
3492 return S_OK;
3495 /******************************************************************************
3496 * VarBstrFromUI2 [OLEAUT32.230]
3498 HRESULT WINAPI VarBstrFromUI2(USHORT uiIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3500 TRACE("( %d, %ld, %ld, %p ), stub\n", uiIn, lcid, dwFlags, pbstrOut );
3501 sprintf( pBuffer, "%d", uiIn );
3502 *pbstrOut = StringDupAtoBstr( pBuffer );
3504 return S_OK;
3507 /******************************************************************************
3508 * VarBstrFromUI4 [OLEAUT32.231]
3510 HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3512 TRACE("( %ld, %ld, %ld, %p ), stub\n", ulIn, lcid, dwFlags, pbstrOut );
3513 sprintf( pBuffer, "%ld", ulIn );
3514 *pbstrOut = StringDupAtoBstr( pBuffer );
3516 return S_OK;
3519 /******************************************************************************
3520 * VarBoolFromUI1 [OLEAUT32.118]
3522 HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL* pboolOut)
3524 TRACE("( %d, %p ), stub\n", bIn, pboolOut );
3526 if( bIn == 0 )
3528 *pboolOut = VARIANT_FALSE;
3530 else
3532 *pboolOut = VARIANT_TRUE;
3535 return S_OK;
3538 /******************************************************************************
3539 * VarBoolFromI2 [OLEAUT32.119]
3541 HRESULT WINAPI VarBoolFromI2(short sIn, VARIANT_BOOL* pboolOut)
3543 TRACE("( %d, %p ), stub\n", sIn, pboolOut );
3545 *pboolOut = (sIn) ? VARIANT_TRUE : VARIANT_FALSE;
3547 return S_OK;
3550 /******************************************************************************
3551 * VarBoolFromI4 [OLEAUT32.120]
3553 HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL* pboolOut)
3555 TRACE("( %ld, %p ), stub\n", lIn, pboolOut );
3557 *pboolOut = (lIn) ? VARIANT_TRUE : VARIANT_FALSE;
3559 return S_OK;
3562 /******************************************************************************
3563 * VarBoolFromR4 [OLEAUT32.121]
3565 HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL* pboolOut)
3567 TRACE("( %f, %p ), stub\n", fltIn, pboolOut );
3569 *pboolOut = (fltIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3571 return S_OK;
3574 /******************************************************************************
3575 * VarBoolFromR8 [OLEAUT32.122]
3577 HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL* pboolOut)
3579 TRACE("( %f, %p ), stub\n", dblIn, pboolOut );
3581 *pboolOut = (dblIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3583 return S_OK;
3586 /******************************************************************************
3587 * VarBoolFromDate [OLEAUT32.123]
3589 HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL* pboolOut)
3591 TRACE("( %f, %p ), stub\n", dateIn, pboolOut );
3593 *pboolOut = (dateIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3595 return S_OK;
3598 /******************************************************************************
3599 * VarBoolFromStr [OLEAUT32.125]
3601 HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL* pboolOut)
3603 HRESULT ret = S_OK;
3604 char* pNewString = NULL;
3606 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pboolOut );
3608 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3610 if( pNewString == NULL || strlen( pNewString ) == 0 )
3612 ret = DISP_E_TYPEMISMATCH;
3615 if( ret == S_OK )
3617 if( strncasecmp( pNewString, "True", strlen( pNewString ) ) == 0 )
3619 *pboolOut = VARIANT_TRUE;
3621 else if( strncasecmp( pNewString, "False", strlen( pNewString ) ) == 0 )
3623 *pboolOut = VARIANT_FALSE;
3625 else
3627 /* Try converting the string to a floating point number.
3629 double dValue = 0.0;
3630 HRESULT res = VarR8FromStr( strIn, lcid, dwFlags, &dValue );
3631 if( res != S_OK )
3633 ret = DISP_E_TYPEMISMATCH;
3635 else
3636 *pboolOut = (dValue == 0.0) ?
3637 VARIANT_FALSE : VARIANT_TRUE;
3641 HeapFree( GetProcessHeap(), 0, pNewString );
3643 return ret;
3646 /******************************************************************************
3647 * VarBoolFromI1 [OLEAUT32.233]
3649 HRESULT WINAPI VarBoolFromI1(CHAR cIn, VARIANT_BOOL* pboolOut)
3651 TRACE("( %c, %p ), stub\n", cIn, pboolOut );
3653 *pboolOut = (cIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3655 return S_OK;
3658 /******************************************************************************
3659 * VarBoolFromUI2 [OLEAUT32.234]
3661 HRESULT WINAPI VarBoolFromUI2(USHORT uiIn, VARIANT_BOOL* pboolOut)
3663 TRACE("( %d, %p ), stub\n", uiIn, pboolOut );
3665 *pboolOut = (uiIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3667 return S_OK;
3670 /******************************************************************************
3671 * VarBoolFromUI4 [OLEAUT32.235]
3673 HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL* pboolOut)
3675 TRACE("( %ld, %p ), stub\n", ulIn, pboolOut );
3677 *pboolOut = (ulIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3679 return S_OK;
3682 /**********************************************************************
3683 * VarBoolFromCy [OLEAUT32.124]
3684 * Convert currency to boolean
3686 HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL* pboolOut) {
3687 if (cyIn.s.Hi || cyIn.s.Lo) *pboolOut = -1;
3688 else *pboolOut = 0;
3690 return S_OK;
3693 /******************************************************************************
3694 * VarI1FromUI1 [OLEAUT32.244]
3696 HRESULT WINAPI VarI1FromUI1(BYTE bIn, CHAR* pcOut)
3698 TRACE("( %d, %p ), stub\n", bIn, pcOut );
3700 /* Check range of value.
3702 if( bIn > CHAR_MAX )
3704 return DISP_E_OVERFLOW;
3707 *pcOut = (CHAR) bIn;
3709 return S_OK;
3712 /******************************************************************************
3713 * VarI1FromI2 [OLEAUT32.245]
3715 HRESULT WINAPI VarI1FromI2(short uiIn, CHAR* pcOut)
3717 TRACE("( %d, %p ), stub\n", uiIn, pcOut );
3719 if( uiIn > CHAR_MAX )
3721 return DISP_E_OVERFLOW;
3724 *pcOut = (CHAR) uiIn;
3726 return S_OK;
3729 /******************************************************************************
3730 * VarI1FromI4 [OLEAUT32.246]
3732 HRESULT WINAPI VarI1FromI4(LONG lIn, CHAR* pcOut)
3734 TRACE("( %ld, %p ), stub\n", lIn, pcOut );
3736 if( lIn < CHAR_MIN || lIn > CHAR_MAX )
3738 return DISP_E_OVERFLOW;
3741 *pcOut = (CHAR) lIn;
3743 return S_OK;
3746 /******************************************************************************
3747 * VarI1FromR4 [OLEAUT32.247]
3749 HRESULT WINAPI VarI1FromR4(FLOAT fltIn, CHAR* pcOut)
3751 TRACE("( %f, %p ), stub\n", fltIn, pcOut );
3753 fltIn = round( fltIn );
3754 if( fltIn < CHAR_MIN || fltIn > CHAR_MAX )
3756 return DISP_E_OVERFLOW;
3759 *pcOut = (CHAR) fltIn;
3761 return S_OK;
3764 /******************************************************************************
3765 * VarI1FromR8 [OLEAUT32.248]
3767 HRESULT WINAPI VarI1FromR8(double dblIn, CHAR* pcOut)
3769 TRACE("( %f, %p ), stub\n", dblIn, pcOut );
3771 dblIn = round( dblIn );
3772 if( dblIn < CHAR_MIN || dblIn > CHAR_MAX )
3774 return DISP_E_OVERFLOW;
3777 *pcOut = (CHAR) dblIn;
3779 return S_OK;
3782 /******************************************************************************
3783 * VarI1FromDate [OLEAUT32.249]
3785 HRESULT WINAPI VarI1FromDate(DATE dateIn, CHAR* pcOut)
3787 TRACE("( %f, %p ), stub\n", dateIn, pcOut );
3789 dateIn = round( dateIn );
3790 if( dateIn < CHAR_MIN || dateIn > CHAR_MAX )
3792 return DISP_E_OVERFLOW;
3795 *pcOut = (CHAR) dateIn;
3797 return S_OK;
3800 /******************************************************************************
3801 * VarI1FromStr [OLEAUT32.251]
3803 HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, CHAR* pcOut)
3805 double dValue = 0.0;
3806 LPSTR pNewString = NULL;
3808 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pcOut );
3810 /* Check if we have a valid argument
3812 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3813 RemoveCharacterFromString( pNewString, "," );
3814 if( IsValidRealString( pNewString ) == FALSE )
3816 return DISP_E_TYPEMISMATCH;
3819 /* Convert the valid string to a floating point number.
3821 dValue = atof( pNewString );
3823 /* We don't need the string anymore so free it.
3825 HeapFree( GetProcessHeap(), 0, pNewString );
3827 /* Check range of value.
3829 dValue = round( dValue );
3830 if( dValue < CHAR_MIN || dValue > CHAR_MAX )
3832 return DISP_E_OVERFLOW;
3835 *pcOut = (CHAR) dValue;
3837 return S_OK;
3840 /******************************************************************************
3841 * VarI1FromBool [OLEAUT32.253]
3843 HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, CHAR* pcOut)
3845 TRACE("( %d, %p ), stub\n", boolIn, pcOut );
3847 *pcOut = (CHAR) boolIn;
3849 return S_OK;
3852 /******************************************************************************
3853 * VarI1FromUI2 [OLEAUT32.254]
3855 HRESULT WINAPI VarI1FromUI2(USHORT uiIn, CHAR* pcOut)
3857 TRACE("( %d, %p ), stub\n", uiIn, pcOut );
3859 if( uiIn > CHAR_MAX )
3861 return DISP_E_OVERFLOW;
3864 *pcOut = (CHAR) uiIn;
3866 return S_OK;
3869 /******************************************************************************
3870 * VarI1FromUI4 [OLEAUT32.255]
3872 HRESULT WINAPI VarI1FromUI4(ULONG ulIn, CHAR* pcOut)
3874 TRACE("( %ld, %p ), stub\n", ulIn, pcOut );
3876 if( ulIn > CHAR_MAX )
3878 return DISP_E_OVERFLOW;
3881 *pcOut = (CHAR) ulIn;
3883 return S_OK;
3886 /**********************************************************************
3887 * VarI1FromCy [OLEAUT32.250]
3888 * Convert currency to signed char
3890 HRESULT WINAPI VarI1FromCy(CY cyIn, CHAR* pcOut) {
3891 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3893 if (t > CHAR_MAX || t < CHAR_MIN) return DISP_E_OVERFLOW;
3895 *pcOut = (CHAR)t;
3896 return S_OK;
3899 /******************************************************************************
3900 * VarUI2FromUI1 [OLEAUT32.257]
3902 HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* puiOut)
3904 TRACE("( %d, %p ), stub\n", bIn, puiOut );
3906 *puiOut = (USHORT) bIn;
3908 return S_OK;
3911 /******************************************************************************
3912 * VarUI2FromI2 [OLEAUT32.258]
3914 HRESULT WINAPI VarUI2FromI2(short uiIn, USHORT* puiOut)
3916 TRACE("( %d, %p ), stub\n", uiIn, puiOut );
3918 if( uiIn < UI2_MIN )
3920 return DISP_E_OVERFLOW;
3923 *puiOut = (USHORT) uiIn;
3925 return S_OK;
3928 /******************************************************************************
3929 * VarUI2FromI4 [OLEAUT32.259]
3931 HRESULT WINAPI VarUI2FromI4(LONG lIn, USHORT* puiOut)
3933 TRACE("( %ld, %p ), stub\n", lIn, puiOut );
3935 if( lIn < UI2_MIN || lIn > UI2_MAX )
3937 return DISP_E_OVERFLOW;
3940 *puiOut = (USHORT) lIn;
3942 return S_OK;
3945 /******************************************************************************
3946 * VarUI2FromR4 [OLEAUT32.260]
3948 HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* puiOut)
3950 TRACE("( %f, %p ), stub\n", fltIn, puiOut );
3952 fltIn = round( fltIn );
3953 if( fltIn < UI2_MIN || fltIn > UI2_MAX )
3955 return DISP_E_OVERFLOW;
3958 *puiOut = (USHORT) fltIn;
3960 return S_OK;
3963 /******************************************************************************
3964 * VarUI2FromR8 [OLEAUT32.261]
3966 HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* puiOut)
3968 TRACE("( %f, %p ), stub\n", dblIn, puiOut );
3970 dblIn = round( dblIn );
3971 if( dblIn < UI2_MIN || dblIn > UI2_MAX )
3973 return DISP_E_OVERFLOW;
3976 *puiOut = (USHORT) dblIn;
3978 return S_OK;
3981 /******************************************************************************
3982 * VarUI2FromDate [OLEAUT32.262]
3984 HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* puiOut)
3986 TRACE("( %f, %p ), stub\n", dateIn, puiOut );
3988 dateIn = round( dateIn );
3989 if( dateIn < UI2_MIN || dateIn > UI2_MAX )
3991 return DISP_E_OVERFLOW;
3994 *puiOut = (USHORT) dateIn;
3996 return S_OK;
3999 /******************************************************************************
4000 * VarUI2FromStr [OLEAUT32.264]
4002 HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* puiOut)
4004 double dValue = 0.0;
4005 LPSTR pNewString = NULL;
4007 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, puiOut );
4009 /* Check if we have a valid argument
4011 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
4012 RemoveCharacterFromString( pNewString, "," );
4013 if( IsValidRealString( pNewString ) == FALSE )
4015 return DISP_E_TYPEMISMATCH;
4018 /* Convert the valid string to a floating point number.
4020 dValue = atof( pNewString );
4022 /* We don't need the string anymore so free it.
4024 HeapFree( GetProcessHeap(), 0, pNewString );
4026 /* Check range of value.
4028 dValue = round( dValue );
4029 if( dValue < UI2_MIN || dValue > UI2_MAX )
4031 return DISP_E_OVERFLOW;
4034 *puiOut = (USHORT) dValue;
4036 return S_OK;
4039 /******************************************************************************
4040 * VarUI2FromBool [OLEAUT32.266]
4042 HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* puiOut)
4044 TRACE("( %d, %p ), stub\n", boolIn, puiOut );
4046 *puiOut = (USHORT) boolIn;
4048 return S_OK;
4051 /******************************************************************************
4052 * VarUI2FromI1 [OLEAUT32.267]
4054 HRESULT WINAPI VarUI2FromI1(CHAR cIn, USHORT* puiOut)
4056 TRACE("( %c, %p ), stub\n", cIn, puiOut );
4058 *puiOut = (USHORT) cIn;
4060 return S_OK;
4063 /******************************************************************************
4064 * VarUI2FromUI4 [OLEAUT32.268]
4066 HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* puiOut)
4068 TRACE("( %ld, %p ), stub\n", ulIn, puiOut );
4070 if( ulIn > UI2_MAX )
4072 return DISP_E_OVERFLOW;
4075 *puiOut = (USHORT) ulIn;
4077 return S_OK;
4080 /******************************************************************************
4081 * VarUI4FromStr [OLEAUT32.277]
4083 HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG* pulOut)
4085 double dValue = 0.0;
4086 LPSTR pNewString = NULL;
4088 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pulOut );
4090 /* Check if we have a valid argument
4092 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
4093 RemoveCharacterFromString( pNewString, "," );
4094 if( IsValidRealString( pNewString ) == FALSE )
4096 return DISP_E_TYPEMISMATCH;
4099 /* Convert the valid string to a floating point number.
4101 dValue = atof( pNewString );
4103 /* We don't need the string anymore so free it.
4105 HeapFree( GetProcessHeap(), 0, pNewString );
4107 /* Check range of value.
4109 dValue = round( dValue );
4110 if( dValue < UI4_MIN || dValue > UI4_MAX )
4112 return DISP_E_OVERFLOW;
4115 *pulOut = (ULONG) dValue;
4117 return S_OK;
4120 /**********************************************************************
4121 * VarUI2FromCy [OLEAUT32.263]
4122 * Convert currency to unsigned short
4124 HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut) {
4125 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
4127 if (t > UI2_MAX || t < UI2_MIN) return DISP_E_OVERFLOW;
4129 *pusOut = (USHORT)t;
4131 return S_OK;
4134 /******************************************************************************
4135 * VarUI4FromUI1 [OLEAUT32.270]
4137 HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG* pulOut)
4139 TRACE("( %d, %p ), stub\n", bIn, pulOut );
4141 *pulOut = (USHORT) bIn;
4143 return S_OK;
4146 /******************************************************************************
4147 * VarUI4FromI2 [OLEAUT32.271]
4149 HRESULT WINAPI VarUI4FromI2(short uiIn, ULONG* pulOut)
4151 TRACE("( %d, %p ), stub\n", uiIn, pulOut );
4153 if( uiIn < UI4_MIN )
4155 return DISP_E_OVERFLOW;
4158 *pulOut = (ULONG) uiIn;
4160 return S_OK;
4163 /******************************************************************************
4164 * VarUI4FromI4 [OLEAUT32.272]
4166 HRESULT WINAPI VarUI4FromI4(LONG lIn, ULONG* pulOut)
4168 TRACE("( %ld, %p ), stub\n", lIn, pulOut );
4170 if( lIn < 0 )
4172 return DISP_E_OVERFLOW;
4175 *pulOut = (ULONG) lIn;
4177 return S_OK;
4180 /******************************************************************************
4181 * VarUI4FromR4 [OLEAUT32.273]
4183 HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG* pulOut)
4185 fltIn = round( fltIn );
4186 if( fltIn < UI4_MIN || fltIn > UI4_MAX )
4188 return DISP_E_OVERFLOW;
4191 *pulOut = (ULONG) fltIn;
4193 return S_OK;
4196 /******************************************************************************
4197 * VarUI4FromR8 [OLEAUT32.274]
4199 HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG* pulOut)
4201 TRACE("( %f, %p ), stub\n", dblIn, pulOut );
4203 dblIn = round( dblIn );
4204 if( dblIn < UI4_MIN || dblIn > UI4_MAX )
4206 return DISP_E_OVERFLOW;
4209 *pulOut = (ULONG) dblIn;
4211 return S_OK;
4214 /******************************************************************************
4215 * VarUI4FromDate [OLEAUT32.275]
4217 HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG* pulOut)
4219 TRACE("( %f, %p ), stub\n", dateIn, pulOut );
4221 dateIn = round( dateIn );
4222 if( dateIn < UI4_MIN || dateIn > UI4_MAX )
4224 return DISP_E_OVERFLOW;
4227 *pulOut = (ULONG) dateIn;
4229 return S_OK;
4232 /******************************************************************************
4233 * VarUI4FromBool [OLEAUT32.279]
4235 HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG* pulOut)
4237 TRACE("( %d, %p ), stub\n", boolIn, pulOut );
4239 *pulOut = (ULONG) boolIn;
4241 return S_OK;
4244 /******************************************************************************
4245 * VarUI4FromI1 [OLEAUT32.280]
4247 HRESULT WINAPI VarUI4FromI1(CHAR cIn, ULONG* pulOut)
4249 TRACE("( %c, %p ), stub\n", cIn, pulOut );
4251 *pulOut = (ULONG) cIn;
4253 return S_OK;
4256 /******************************************************************************
4257 * VarUI4FromUI2 [OLEAUT32.281]
4259 HRESULT WINAPI VarUI4FromUI2(USHORT uiIn, ULONG* pulOut)
4261 TRACE("( %d, %p ), stub\n", uiIn, pulOut );
4263 *pulOut = (ULONG) uiIn;
4265 return S_OK;
4268 /**********************************************************************
4269 * VarUI4FromCy [OLEAUT32.276]
4270 * Convert currency to unsigned long
4272 HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG* pulOut) {
4273 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
4275 if (t > UI4_MAX || t < UI4_MIN) return DISP_E_OVERFLOW;
4277 *pulOut = (ULONG)t;
4279 return S_OK;
4282 /**********************************************************************
4283 * VarCyFromUI1 [OLEAUT32.98]
4284 * Convert unsigned char to currency
4286 HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pcyOut) {
4287 pcyOut->s.Hi = 0;
4288 pcyOut->s.Lo = ((ULONG)bIn) * 10000;
4290 return S_OK;
4293 /**********************************************************************
4294 * VarCyFromI2 [OLEAUT32.99]
4295 * Convert signed short to currency
4297 HRESULT WINAPI VarCyFromI2(short sIn, CY* pcyOut) {
4298 if (sIn < 0) pcyOut->s.Hi = -1;
4299 else pcyOut->s.Hi = 0;
4300 pcyOut->s.Lo = ((ULONG)sIn) * 10000;
4302 return S_OK;
4305 /**********************************************************************
4306 * VarCyFromI4 [OLEAUT32.100]
4307 * Convert signed long to currency
4309 HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pcyOut) {
4310 double t = (double)lIn * (double)10000;
4311 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4312 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4313 if (lIn < 0) pcyOut->s.Hi--;
4315 return S_OK;
4318 /**********************************************************************
4319 * VarCyFromR4 [OLEAUT32.101]
4320 * Convert float to currency
4322 HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pcyOut) {
4323 double t = round((double)fltIn * (double)10000);
4324 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4325 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4326 if (fltIn < 0) pcyOut->s.Hi--;
4328 return S_OK;
4331 /**********************************************************************
4332 * VarCyFromR8 [OLEAUT32.102]
4333 * Convert double to currency
4335 HRESULT WINAPI VarCyFromR8(double dblIn, CY* pcyOut) {
4336 double t = round(dblIn * (double)10000);
4337 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4338 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4339 if (dblIn < 0) pcyOut->s.Hi--;
4341 return S_OK;
4344 /**********************************************************************
4345 * VarCyFromDate [OLEAUT32.103]
4346 * Convert date to currency
4348 HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pcyOut) {
4349 double t = round((double)dateIn * (double)10000);
4350 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4351 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4352 if (dateIn < 0) pcyOut->s.Hi--;
4354 return S_OK;
4357 /**********************************************************************
4358 * VarCyFromStr [OLEAUT32.104]
4359 * FIXME: Never tested with decimal seperator other than '.'
4361 HRESULT WINAPI VarCyFromStr(OLECHAR *strIn, LCID lcid, ULONG dwFlags, CY *pcyOut) {
4363 LPSTR pNewString = NULL;
4364 char *decSep = NULL;
4365 char *strPtr,*curPtr = NULL;
4366 int size, rc;
4367 double currencyVal = 0.0;
4370 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
4371 TRACE("( '%s', 0x%08lx, 0x%08lx, %p )\n", pNewString, lcid, dwFlags, pcyOut );
4373 /* Get locale information - Decimal Seperator (size includes 0x00) */
4374 size = GetLocaleInfoA(lcid, LOCALE_SDECIMAL, NULL, 0);
4375 decSep = (char *) malloc(size);
4376 rc = GetLocaleInfoA(lcid, LOCALE_SDECIMAL, decSep, size);
4377 TRACE("Decimal Seperator is '%s'\n", decSep);
4379 /* Now copy to temporary buffer, skipping any character except 0-9 and
4380 the decimal seperator */
4381 curPtr = pBuffer; /* Current position in string being built */
4382 strPtr = pNewString; /* Current position in supplied currenct string */
4384 while (*strPtr) {
4385 /* If decimal seperator, skip it and put '.' in string */
4386 if (strncmp(strPtr, decSep, (size-1)) == 0) {
4387 strPtr = strPtr + (size-1);
4388 *curPtr = '.';
4389 curPtr++;
4390 } else if ((*strPtr == '+' || *strPtr == '-') ||
4391 (*strPtr >= '0' && *strPtr <= '9')) {
4392 *curPtr = *strPtr;
4393 strPtr++;
4394 curPtr++;
4395 } else strPtr++;
4397 *curPtr = 0x00;
4399 /* Try to get currency into a double */
4400 currencyVal = atof(pBuffer);
4401 TRACE("Converted string '%s' to %f\n", pBuffer, currencyVal);
4403 /* Free allocated storage */
4404 HeapFree( GetProcessHeap(), 0, pNewString );
4405 free(decSep);
4407 /* Convert double -> currency using internal routine */
4408 return VarCyFromR8(currencyVal, pcyOut);
4412 /**********************************************************************
4413 * VarCyFromBool [OLEAUT32.106]
4414 * Convert boolean to currency
4416 HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pcyOut) {
4417 if (boolIn < 0) pcyOut->s.Hi = -1;
4418 else pcyOut->s.Hi = 0;
4419 pcyOut->s.Lo = (ULONG)boolIn * (ULONG)10000;
4421 return S_OK;
4424 /**********************************************************************
4425 * VarCyFromI1 [OLEAUT32.225]
4426 * Convert signed char to currency
4428 HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pcyOut) {
4429 if (cIn < 0) pcyOut->s.Hi = -1;
4430 else pcyOut->s.Hi = 0;
4431 pcyOut->s.Lo = (ULONG)cIn * (ULONG)10000;
4433 return S_OK;
4436 /**********************************************************************
4437 * VarCyFromUI2 [OLEAUT32.226]
4438 * Convert unsigned short to currency
4440 HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pcyOut) {
4441 pcyOut->s.Hi = 0;
4442 pcyOut->s.Lo = (ULONG)usIn * (ULONG)10000;
4444 return S_OK;
4447 /**********************************************************************
4448 * VarCyFromUI4 [OLEAUT32.227]
4449 * Convert unsigned long to currency
4451 HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pcyOut) {
4452 double t = (double)ulIn * (double)10000;
4453 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4454 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4456 return S_OK;
4460 /**********************************************************************
4461 * DosDateTimeToVariantTime [OLEAUT32.14]
4462 * Convert dos representation of time to the date and time representation
4463 * stored in a variant.
4465 INT WINAPI DosDateTimeToVariantTime(USHORT wDosDate, USHORT wDosTime,
4466 DATE *pvtime)
4468 struct tm t;
4470 TRACE("( 0x%x, 0x%x, %p ), stub\n", wDosDate, wDosTime, pvtime );
4472 t.tm_sec = (wDosTime & 0x001f) * 2;
4473 t.tm_min = (wDosTime & 0x07e0) >> 5;
4474 t.tm_hour = (wDosTime & 0xf800) >> 11;
4476 t.tm_mday = (wDosDate & 0x001f);
4477 t.tm_mon = (wDosDate & 0x01e0) >> 5;
4478 t.tm_year = ((wDosDate & 0xfe00) >> 9) + 1980;
4480 return TmToDATE( &t, pvtime );
4484 /**********************************************************************
4485 * VarParseNumFromStr [OLEAUT32.46]
4487 HRESULT WINAPI VarParseNumFromStr(OLECHAR * strIn, LCID lcid, ULONG dwFlags,
4488 NUMPARSE * pnumprs, BYTE * rgbDig)
4490 int i,lastent=0;
4491 int cDig;
4492 BOOL foundNum=FALSE;
4494 FIXME("(%s,flags=%lx,....), partial stub!\n",debugstr_w(strIn),dwFlags);
4495 FIXME("numparse: cDig=%d, InFlags=%lx\n",pnumprs->cDig,pnumprs->dwInFlags);
4497 /* The other struct components are to be set by us */
4498 memset(rgbDig,0,pnumprs->cDig);
4500 /* FIXME: Just patching some values in */
4501 pnumprs->nPwr10 = 0;
4502 pnumprs->nBaseShift = 0;
4503 pnumprs->cchUsed = lastent;
4504 pnumprs->dwOutFlags = NUMPRS_DECIMAL;
4506 cDig = 0;
4507 for (i=0; strIn[i] ;i++) {
4508 if ((strIn[i]>='0') && (strIn[i]<='9')) {
4509 foundNum = TRUE;
4510 if (pnumprs->cDig > cDig) {
4511 *(rgbDig++)=strIn[i]-'0';
4512 cDig++;
4513 lastent = i;
4515 } else if ((strIn[i]=='-') && (foundNum==FALSE)) {
4516 pnumprs->dwOutFlags |= NUMPRS_NEG;
4519 pnumprs->cDig = cDig;
4520 TRACE("numparse out: cDig=%d, OutFlags=%lx\n",pnumprs->cDig,pnumprs->dwOutFlags);
4521 return S_OK;
4525 /**********************************************************************
4526 * VarNumFromParseNum [OLEAUT32.47]
4528 HRESULT WINAPI VarNumFromParseNum(NUMPARSE * pnumprs, BYTE * rgbDig,
4529 ULONG dwVtBits, VARIANT * pvar)
4531 DWORD xint;
4532 int i;
4533 FIXME("(..,dwVtBits=%lx,....), partial stub!\n",dwVtBits);
4535 xint = 0;
4536 for (i=0;i<pnumprs->cDig;i++)
4537 xint = xint*10 + rgbDig[i];
4539 if (pnumprs->dwOutFlags & NUMPRS_NEG) {
4540 xint = xint * -1;
4543 VariantInit(pvar);
4544 if (dwVtBits & VTBIT_I4) {
4545 V_VT(pvar) = VT_I4;
4546 V_UNION(pvar,intVal) = xint;
4547 return S_OK;
4549 if (dwVtBits & VTBIT_R8) {
4550 V_VT(pvar) = VT_R8;
4551 V_UNION(pvar,dblVal) = xint;
4552 return S_OK;
4554 if (dwVtBits & VTBIT_R4) {
4555 V_VT(pvar) = VT_R4;
4556 V_UNION(pvar,fltVal) = xint;
4557 return S_OK;
4559 if (dwVtBits & VTBIT_I2) {
4560 V_VT(pvar) = VT_I2;
4561 V_UNION(pvar,iVal) = xint;
4562 return S_OK;
4564 /* FIXME: Currency should be from a double */
4565 if (dwVtBits & VTBIT_CY) {
4566 V_VT(pvar) = VT_CY;
4567 TRACE("Calculated currency is xint=%ld\n", xint);
4568 VarCyFromInt( (int) xint, &V_UNION(pvar,cyVal) );
4569 TRACE("Calculated cy is %ld,%lu\n", V_UNION(pvar,cyVal).s.Hi, V_UNION(pvar,cyVal).s.Lo);
4570 return VarCyFromInt( (int) xint, &V_UNION(pvar,cyVal) );
4573 FIXME("vtbitmask is unsupported %lx, int=%d\n",dwVtBits, (int) xint);
4574 return E_FAIL;
4578 /**********************************************************************
4579 * VarFormatDateTime [OLEAUT32.97]
4581 HRESULT WINAPI VarFormatDateTime(LPVARIANT var, INT format, ULONG dwFlags, BSTR *out)
4583 FIXME("%p %d %lx %p\n", var, format, dwFlags, out);
4584 return E_NOTIMPL;
4587 /**********************************************************************
4588 * VarFormatCurrency [OLEAUT32.127]
4590 HRESULT WINAPI VarFormatCurrency(LPVARIANT var, INT digits, INT lead, INT paren, INT group, ULONG dwFlags, BSTR *out)
4592 FIXME("%p %d %d %d %d %lx %p\n", var, digits, lead, paren, group, dwFlags, out);
4593 return E_NOTIMPL;
4596 /**********************************************************************
4597 * VariantTimeToDosDateTime [OLEAUT32.13]
4598 * Convert variant representation of time to the date and time representation
4599 * stored in dos.
4601 INT WINAPI VariantTimeToDosDateTime(DATE pvtime, USHORT *wDosDate, USHORT *wDosTime)
4603 struct tm t;
4604 *wDosTime = 0;
4605 *wDosDate = 0;
4607 TRACE("( 0x%x, 0x%x, %p ), stub\n", *wDosDate, *wDosTime, &pvtime );
4609 if (DateToTm(pvtime, 0, &t) < 0) return 0;
4611 *wDosTime = *wDosTime | (t.tm_sec / 2);
4612 *wDosTime = *wDosTime | (t.tm_min << 5);
4613 *wDosTime = *wDosTime | (t.tm_hour << 11);
4615 *wDosDate = *wDosDate | t.tm_mday ;
4616 *wDosDate = *wDosDate | t.tm_mon << 5;
4617 *wDosDate = *wDosDate | ((t.tm_year - 1980) << 9) ;
4619 return 1;
4623 /***********************************************************************
4624 * SystemTimeToVariantTime [OLEAUT32.184]
4626 HRESULT WINAPI SystemTimeToVariantTime( LPSYSTEMTIME lpSystemTime, double *pvtime )
4628 struct tm t;
4630 TRACE(" %d/%d/%d %d:%d:%d\n",
4631 lpSystemTime->wMonth, lpSystemTime->wDay,
4632 lpSystemTime->wYear, lpSystemTime->wHour,
4633 lpSystemTime->wMinute, lpSystemTime->wSecond);
4635 if (lpSystemTime->wYear >= 1900)
4637 t.tm_sec = lpSystemTime->wSecond;
4638 t.tm_min = lpSystemTime->wMinute;
4639 t.tm_hour = lpSystemTime->wHour;
4641 t.tm_mday = lpSystemTime->wDay;
4642 t.tm_mon = lpSystemTime->wMonth - 1; /* tm_mon is 0..11, wMonth is 1..12 */
4643 t.tm_year = lpSystemTime->wYear;
4645 return TmToDATE( &t, pvtime );
4647 else
4649 double tmpDate;
4650 long firstDayOfNextYear;
4651 long thisDay;
4652 long leftInYear;
4653 long result;
4655 double decimalPart = 0.0;
4657 t.tm_sec = lpSystemTime->wSecond;
4658 t.tm_min = lpSystemTime->wMinute;
4659 t.tm_hour = lpSystemTime->wHour;
4661 /* Step year forward the same number of years before 1900 */
4662 t.tm_year = 1900 + 1899 - lpSystemTime->wYear;
4663 t.tm_mon = lpSystemTime->wMonth - 1;
4664 t.tm_mday = lpSystemTime->wDay;
4666 /* Calculate date */
4667 TmToDATE( &t, pvtime );
4669 thisDay = (double) floor( *pvtime );
4670 decimalPart = fmod( *pvtime, thisDay );
4672 /* Now, calculate the same time for the first of Jan that year */
4673 t.tm_mon = 0;
4674 t.tm_mday = 1;
4675 t.tm_sec = 0;
4676 t.tm_min = 0;
4677 t.tm_hour = 0;
4678 t.tm_year = t.tm_year+1;
4679 TmToDATE( &t, &tmpDate );
4680 firstDayOfNextYear = (long) floor(tmpDate);
4682 /* Finally since we know the size of the year, subtract the two to get
4683 remaining time in the year */
4684 leftInYear = firstDayOfNextYear - thisDay;
4686 /* Now we want full years up to the year in question, and remainder of year
4687 of the year in question */
4688 if (isleap(lpSystemTime->wYear) ) {
4689 TRACE("Extra day due to leap year\n");
4690 result = 2.0 - ((firstDayOfNextYear - 366) + leftInYear - 2.0);
4691 } else {
4692 result = 2.0 - ((firstDayOfNextYear - 365) + leftInYear - 2.0);
4694 *pvtime = (double) result + decimalPart;
4695 TRACE("<1899 support: returned %f, 1st day %ld, thisday %ld, left %ld\n", *pvtime, firstDayOfNextYear, thisDay, leftInYear);
4697 return 1;
4700 return 0;
4703 /***********************************************************************
4704 * VariantTimeToSystemTime [OLEAUT32.185]
4706 HRESULT WINAPI VariantTimeToSystemTime( double vtime, LPSYSTEMTIME lpSystemTime )
4708 double t = 0, timeofday = 0;
4710 static const BYTE Days_Per_Month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4711 static const BYTE Days_Per_Month_LY[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4713 /* The Month_Code is used to find the Day of the Week (LY = LeapYear)*/
4714 static const BYTE Month_Code[] = {0, 1, 4, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6};
4715 static const BYTE Month_Code_LY[] = {0, 0, 3, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6};
4717 /* The Century_Code is used to find the Day of the Week */
4718 static const BYTE Century_Code[] = {0, 6, 4, 2};
4720 struct tm r;
4722 TRACE(" Variant = %f SYSTEMTIME ptr %p\n", vtime, lpSystemTime);
4724 if (vtime >= 0)
4727 if (DateToTm(vtime, 0, &r ) <= 0) return 0;
4729 lpSystemTime->wSecond = r.tm_sec;
4730 lpSystemTime->wMinute = r.tm_min;
4731 lpSystemTime->wHour = r.tm_hour;
4732 lpSystemTime->wDay = r.tm_mday;
4733 lpSystemTime->wMonth = r.tm_mon;
4735 if (lpSystemTime->wMonth == 12)
4736 lpSystemTime->wMonth = 1;
4737 else
4738 lpSystemTime->wMonth++;
4740 lpSystemTime->wYear = r.tm_year;
4742 else
4744 vtime = -1*vtime;
4746 if (DateToTm(vtime, 0, &r ) <= 0) return 0;
4748 lpSystemTime->wSecond = r.tm_sec;
4749 lpSystemTime->wMinute = r.tm_min;
4750 lpSystemTime->wHour = r.tm_hour;
4752 lpSystemTime->wMonth = 13 - r.tm_mon;
4754 if (lpSystemTime->wMonth == 1)
4755 lpSystemTime->wMonth = 12;
4756 else
4757 lpSystemTime->wMonth--;
4759 lpSystemTime->wYear = 1899 - (r.tm_year - 1900);
4761 if (!isleap(lpSystemTime->wYear) )
4762 lpSystemTime->wDay = Days_Per_Month[13 - lpSystemTime->wMonth] - r.tm_mday;
4763 else
4764 lpSystemTime->wDay = Days_Per_Month_LY[13 - lpSystemTime->wMonth] - r.tm_mday;
4769 if (!isleap(lpSystemTime->wYear))
4772 (Century_Code+Month_Code+Year_Code+Day) % 7
4774 The century code repeats every 400 years , so the array
4775 works out like this,
4777 Century_Code[0] is for 16th/20th Centry
4778 Century_Code[1] is for 17th/21th Centry
4779 Century_Code[2] is for 18th/22th Centry
4780 Century_Code[3] is for 19th/23th Centry
4782 The year code is found with the formula (year + (year / 4))
4783 the "year" must be between 0 and 99 .
4785 The Month Code (Month_Code[1]) starts with January and
4786 ends with December.
4789 lpSystemTime->wDayOfWeek = (
4790 Century_Code[(( (lpSystemTime->wYear+100) - lpSystemTime->wYear%100) /100) %4]+
4791 ((lpSystemTime->wYear%100)+(lpSystemTime->wYear%100)/4)+
4792 Month_Code[lpSystemTime->wMonth]+
4793 lpSystemTime->wDay) % 7;
4795 if (lpSystemTime->wDayOfWeek == 0) lpSystemTime->wDayOfWeek = 7;
4796 else lpSystemTime->wDayOfWeek -= 1;
4798 else
4800 lpSystemTime->wDayOfWeek = (
4801 Century_Code[(((lpSystemTime->wYear+100) - lpSystemTime->wYear%100)/100)%4]+
4802 ((lpSystemTime->wYear%100)+(lpSystemTime->wYear%100)/4)+
4803 Month_Code_LY[lpSystemTime->wMonth]+
4804 lpSystemTime->wDay) % 7;
4806 if (lpSystemTime->wDayOfWeek == 0) lpSystemTime->wDayOfWeek = 7;
4807 else lpSystemTime->wDayOfWeek -= 1;
4810 t = floor(vtime);
4811 timeofday = vtime - t;
4813 lpSystemTime->wMilliseconds = (timeofday
4814 - lpSystemTime->wHour*(1/24)
4815 - lpSystemTime->wMinute*(1/1440)
4816 - lpSystemTime->wSecond*(1/86400) )*(1/5184000);
4818 return 1;
4821 /***********************************************************************
4822 * VarUdateFromDate [OLEAUT32.331]
4824 HRESULT WINAPI VarUdateFromDate( DATE datein, ULONG dwFlags, UDATE *pudateout)
4826 HRESULT i = 0;
4827 static const BYTE Days_Per_Month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4828 static const BYTE Days_Per_Month_LY[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4830 TRACE("DATE = %f\n", (double)datein);
4831 i = VariantTimeToSystemTime(datein, &(pudateout->st) );
4833 if (i)
4835 pudateout->wDayOfYear = 0;
4837 if (isleap(pudateout->st.wYear))
4839 for (i =1; i<pudateout->st.wMonth; i++)
4840 pudateout->wDayOfYear += Days_Per_Month[i];
4842 else
4844 for (i =1; i<pudateout->st.wMonth; i++)
4845 pudateout->wDayOfYear += Days_Per_Month_LY[i];
4848 pudateout->wDayOfYear += pudateout->st.wDay;
4849 dwFlags = 0; /*VAR_VALIDDATE*/
4851 else dwFlags = 0;
4853 return i;
4856 /***********************************************************************
4857 * VarDateFromUdate [OLEAUT32.330]
4859 HRESULT WINAPI VarDateFromUdate(UDATE *pudateout,
4860 ULONG dwFlags, DATE *datein)
4862 HRESULT i;
4863 double t = 0;
4864 TRACE(" %d/%d/%d %d:%d:%d\n",
4865 pudateout->st.wMonth, pudateout->st.wDay,
4866 pudateout->st.wYear, pudateout->st.wHour,
4867 pudateout->st.wMinute, pudateout->st.wSecond);
4870 i = SystemTimeToVariantTime(&(pudateout->st), &t);
4871 *datein = t;
4873 if (i) return S_OK;
4874 else return E_INVALIDARG;
4878 /**********************************************************************
4879 * VarBstrCmp [OLEAUT32.314]
4881 * flags can be:
4882 * NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS
4883 * NORM_IGNORESTRINGWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA
4886 HRESULT WINAPI VarBstrCmp(BSTR left, BSTR right, LCID lcid, DWORD flags)
4888 INT r;
4890 TRACE("( %s %s %ld %lx ) partial stub\n", debugstr_w(left), debugstr_w(right), lcid, flags);
4892 /* Contrary to the MSDN, this returns eq for null vs null, null vs L"" and L"" vs NULL */
4893 if((!left) || (!right)) {
4895 if (!left && (!right || *right==0)) return VARCMP_EQ;
4896 else if (!right && (!left || *left==0)) return VARCMP_EQ;
4897 else return VARCMP_NULL;
4900 if(flags&NORM_IGNORECASE)
4901 r = lstrcmpiW(left,right);
4902 else
4903 r = lstrcmpW(left,right);
4905 if(r<0)
4906 return VARCMP_LT;
4907 if(r>0)
4908 return VARCMP_GT;
4910 return VARCMP_EQ;
4913 /**********************************************************************
4914 * VarBstrCat [OLEAUT32.313]
4916 HRESULT WINAPI VarBstrCat(BSTR left, BSTR right, BSTR *out)
4918 BSTR result;
4919 int size = 0;
4921 TRACE("( %s %s %p )\n", debugstr_w(left), debugstr_w(right), out);
4923 /* On Windows, NULL parms are still handled (as empty strings) */
4924 if (left) size=size + lstrlenW(left);
4925 if (right) size=size + lstrlenW(right);
4927 if (out) {
4928 result = SysAllocStringLen(NULL, size);
4929 *out = result;
4930 if (left) lstrcatW(result,left);
4931 if (right) lstrcatW(result,right);
4932 TRACE("result = %s, [%p]\n", debugstr_w(result), result);
4934 return S_OK;
4937 /**********************************************************************
4938 * VarCat [OLEAUT32.318]
4940 HRESULT WINAPI VarCat(LPVARIANT left, LPVARIANT right, LPVARIANT out)
4942 /* Should we VariantClear out? */
4943 /* Can we handle array, vector, by ref etc. */
4944 if ((V_VT(left)&VT_TYPEMASK) == VT_NULL &&
4945 (V_VT(right)&VT_TYPEMASK) == VT_NULL)
4947 V_VT(out) = VT_NULL;
4948 return S_OK;
4950 else if (V_VT(left) == VT_BSTR && V_VT(right) == VT_BSTR)
4952 V_VT(out) = VT_BSTR;
4953 VarBstrCat (V_BSTR(left), V_BSTR(right), &V_BSTR(out));
4954 return S_OK;
4956 else
4957 FIXME ("types not supported\n");
4958 return S_OK;
4961 /**********************************************************************
4962 * VarCmp [OLEAUT32.176]
4964 * flags can be:
4965 * NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS
4966 * NORM_IGNOREWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA
4969 HRESULT WINAPI VarCmp(LPVARIANT left, LPVARIANT right, LCID lcid, DWORD flags)
4973 BOOL lOk = TRUE;
4974 BOOL rOk = TRUE;
4975 LONGLONG lVal = -1;
4976 LONGLONG rVal = -1;
4978 TRACE("Left Var:\n");
4979 dump_Variant(left);
4980 TRACE("Right Var:\n");
4981 dump_Variant(right);
4983 /* If either are null, then return VARCMP_NULL */
4984 if ((V_VT(left)&VT_TYPEMASK) == VT_NULL ||
4985 (V_VT(right)&VT_TYPEMASK) == VT_NULL)
4986 return VARCMP_NULL;
4988 /* Strings - use VarBstrCmp */
4989 if ((V_VT(left)&VT_TYPEMASK) == VT_BSTR &&
4990 (V_VT(right)&VT_TYPEMASK) == VT_BSTR) {
4991 return VarBstrCmp(V_BSTR(left), V_BSTR(right), lcid, flags);
4994 /* Integers - Ideally like to use VarDecCmp, but no Dec support yet
4995 Use LONGLONG to maximize ranges */
4996 lOk = TRUE;
4997 switch (V_VT(left)&VT_TYPEMASK) {
4998 case VT_I1 : lVal = V_UNION(left,cVal); break;
4999 case VT_I2 : lVal = V_UNION(left,iVal); break;
5000 case VT_I4 : lVal = V_UNION(left,lVal); break;
5001 case VT_INT : lVal = V_UNION(left,lVal); break;
5002 case VT_UI1 : lVal = V_UNION(left,bVal); break;
5003 case VT_UI2 : lVal = V_UNION(left,uiVal); break;
5004 case VT_UI4 : lVal = V_UNION(left,ulVal); break;
5005 case VT_UINT : lVal = V_UNION(left,ulVal); break;
5006 default: lOk = FALSE;
5009 rOk = TRUE;
5010 switch (V_VT(right)&VT_TYPEMASK) {
5011 case VT_I1 : rVal = V_UNION(right,cVal); break;
5012 case VT_I2 : rVal = V_UNION(right,iVal); break;
5013 case VT_I4 : rVal = V_UNION(right,lVal); break;
5014 case VT_INT : rVal = V_UNION(right,lVal); break;
5015 case VT_UI1 : rVal = V_UNION(right,bVal); break;
5016 case VT_UI2 : rVal = V_UNION(right,uiVal); break;
5017 case VT_UI4 : rVal = V_UNION(right,ulVal); break;
5018 case VT_UINT : rVal = V_UNION(right,ulVal); break;
5019 default: rOk = FALSE;
5022 if (lOk && rOk) {
5023 if (lVal < rVal) {
5024 return VARCMP_LT;
5025 } else if (lVal > rVal) {
5026 return VARCMP_GT;
5027 } else {
5028 return VARCMP_EQ;
5032 /* Strings - use VarBstrCmp */
5033 if ((V_VT(left)&VT_TYPEMASK) == VT_DATE &&
5034 (V_VT(right)&VT_TYPEMASK) == VT_DATE) {
5036 if (floor(V_UNION(left,date)) == floor(V_UNION(right,date))) {
5037 /* Due to floating point rounding errors, calculate varDate in whole numbers) */
5038 double wholePart = 0.0;
5039 double leftR;
5040 double rightR;
5042 /* Get the fraction * 24*60*60 to make it into whole seconds */
5043 wholePart = (double) floor( V_UNION(left,date) );
5044 if (wholePart == 0) wholePart = 1;
5045 leftR = floor(fmod( V_UNION(left,date), wholePart ) * (24*60*60));
5047 wholePart = (double) floor( V_UNION(right,date) );
5048 if (wholePart == 0) wholePart = 1;
5049 rightR = floor(fmod( V_UNION(right,date), wholePart ) * (24*60*60));
5051 if (leftR < rightR) {
5052 return VARCMP_LT;
5053 } else if (leftR > rightR) {
5054 return VARCMP_GT;
5055 } else {
5056 return VARCMP_EQ;
5059 } else if (V_UNION(left,date) < V_UNION(right,date)) {
5060 return VARCMP_LT;
5061 } else if (V_UNION(left,date) > V_UNION(right,date)) {
5062 return VARCMP_GT;
5067 FIXME("VarCmp partial implementation, doesnt support these pair of variant types");
5068 return E_FAIL;
5071 /**********************************************************************
5072 * VarAnd [OLEAUT32.142]
5075 HRESULT WINAPI VarAnd(LPVARIANT left, LPVARIANT right, LPVARIANT result)
5077 HRESULT rc = E_FAIL;
5079 TRACE("Left Var:\n");
5080 dump_Variant(left);
5081 TRACE("Right Var:\n");
5082 dump_Variant(right);
5084 if ((V_VT(left)&VT_TYPEMASK) == VT_BOOL &&
5085 (V_VT(right)&VT_TYPEMASK) == VT_BOOL) {
5087 V_VT(result) = VT_BOOL;
5088 if (V_BOOL(left) && V_BOOL(right)) {
5089 V_BOOL(result) = VARIANT_TRUE;
5090 } else {
5091 V_BOOL(result) = VARIANT_FALSE;
5093 rc = S_OK;
5095 } else {
5096 /* Integers */
5097 BOOL lOk = TRUE;
5098 BOOL rOk = TRUE;
5099 LONGLONG lVal = -1;
5100 LONGLONG rVal = -1;
5101 LONGLONG res = -1;
5102 int resT = 0; /* Testing has shown I2 & I2 == I2, all else
5103 becomes I4, even unsigned ints (incl. UI2) */
5105 lOk = TRUE;
5106 switch (V_VT(left)&VT_TYPEMASK) {
5107 case VT_I1 : lVal = V_UNION(left,cVal); resT=VT_I4; break;
5108 case VT_I2 : lVal = V_UNION(left,iVal); resT=VT_I2; break;
5109 case VT_I4 : lVal = V_UNION(left,lVal); resT=VT_I4; break;
5110 case VT_INT : lVal = V_UNION(left,lVal); resT=VT_I4; break;
5111 case VT_UI1 : lVal = V_UNION(left,bVal); resT=VT_I4; break;
5112 case VT_UI2 : lVal = V_UNION(left,uiVal); resT=VT_I4; break;
5113 case VT_UI4 : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5114 case VT_UINT : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5115 default: lOk = FALSE;
5118 rOk = TRUE;
5119 switch (V_VT(right)&VT_TYPEMASK) {
5120 case VT_I1 : rVal = V_UNION(right,cVal); resT=VT_I4; break;
5121 case VT_I2 : rVal = V_UNION(right,iVal); resT=max(VT_I2, resT); break;
5122 case VT_I4 : rVal = V_UNION(right,lVal); resT=VT_I4; break;
5123 case VT_INT : rVal = V_UNION(right,lVal); resT=VT_I4; break;
5124 case VT_UI1 : rVal = V_UNION(right,bVal); resT=VT_I4; break;
5125 case VT_UI2 : rVal = V_UNION(right,uiVal); resT=VT_I4; break;
5126 case VT_UI4 : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5127 case VT_UINT : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5128 default: rOk = FALSE;
5131 if (lOk && rOk) {
5132 res = (lVal & rVal);
5133 V_VT(result) = resT;
5134 switch (resT) {
5135 case VT_I2 : V_UNION(result,iVal) = res; break;
5136 case VT_I4 : V_UNION(result,lVal) = res; break;
5137 default:
5138 FIXME("Unexpected result variant type %x\n", resT);
5139 V_UNION(result,lVal) = res;
5141 rc = S_OK;
5143 } else {
5144 FIXME("VarAnd stub\n");
5148 TRACE("rc=%d, Result:\n", (int) rc);
5149 dump_Variant(result);
5150 return rc;
5153 /**********************************************************************
5154 * VarNot [OLEAUT32.174]
5157 HRESULT WINAPI VarNot(LPVARIANT in, LPVARIANT result)
5159 HRESULT rc = E_FAIL;
5161 TRACE("Var In:\n");
5162 dump_Variant(in);
5164 if ((V_VT(in)&VT_TYPEMASK) == VT_BOOL) {
5166 V_VT(result) = VT_BOOL;
5167 if (V_BOOL(in)) {
5168 V_BOOL(result) = VARIANT_FALSE;
5169 } else {
5170 V_BOOL(result) = VARIANT_TRUE;
5172 rc = S_OK;
5174 } else {
5175 FIXME("VarNot stub\n");
5178 TRACE("rc=%d, Result:\n", (int) rc);
5179 dump_Variant(result);
5180 return rc;
5183 /**********************************************************************
5184 * VarTokenizeFormatString [OLEAUT32.140]
5186 * From investigation on W2K, a list is built up which is:
5188 * <0x00> AA BB - Copy from AA for BB chars (Note 1 byte with wrap!)
5189 * <token> - Insert appropriate token
5192 HRESULT WINAPI VarTokenizeFormatString(LPOLESTR format, LPBYTE rgbTok,
5193 int cbTok, int iFirstDay, int iFirstWeek,
5194 LCID lcid, int *pcbActual) {
5196 FORMATHDR *hdr;
5197 int realLen, formatLeft;
5198 BYTE *pData;
5199 LPSTR pFormatA, pStart;
5200 int checkStr;
5201 BOOL insertCopy = FALSE;
5202 LPSTR copyFrom = NULL;
5204 TRACE("'%s', %p %d %d %d only date support\n", debugstr_w(format), rgbTok, cbTok,
5205 iFirstDay, iFirstWeek);
5207 /* Big enough for header? */
5208 if (cbTok < sizeof(FORMATHDR)) {
5209 return TYPE_E_BUFFERTOOSMALL;
5212 /* Insert header */
5213 hdr = (FORMATHDR *) rgbTok;
5214 memset(hdr, 0x00, sizeof(FORMATHDR));
5215 hdr->hex3 = 0x03; /* No idea what these are */
5216 hdr->hex6 = 0x06;
5218 /* Start parsing string */
5219 realLen = sizeof(FORMATHDR);
5220 pData = rgbTok + realLen;
5221 pFormatA = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
5222 pStart = pFormatA;
5223 formatLeft = strlen(pFormatA);
5225 /* Work through the format */
5226 while (*pFormatA != 0x00) {
5228 checkStr = 0;
5229 while (checkStr>=0 && (formatTokens[checkStr].tokenSize != 0x00)) {
5230 if (formatLeft >= formatTokens[checkStr].tokenSize &&
5231 strncmp(formatTokens[checkStr].str, pFormatA,
5232 formatTokens[checkStr].tokenSize) == 0) {
5233 TRACE("match on '%s'\n", formatTokens[checkStr].str);
5235 /* Found Match! */
5237 /* If we have skipped chars, insert the copy */
5238 if (insertCopy == TRUE) {
5240 if ((realLen + 3) > cbTok) {
5241 HeapFree( GetProcessHeap(), 0, pFormatA );
5242 return TYPE_E_BUFFERTOOSMALL;
5244 insertCopy = FALSE;
5245 *pData = TOK_COPY;
5246 pData++;
5247 *pData = (BYTE)(copyFrom - pStart);
5248 pData++;
5249 *pData = (BYTE)(pFormatA - copyFrom);
5250 pData++;
5251 realLen = realLen + 3;
5255 /* Now insert the token itself */
5256 if ((realLen + 1) > cbTok) {
5257 HeapFree( GetProcessHeap(), 0, pFormatA );
5258 return TYPE_E_BUFFERTOOSMALL;
5260 *pData = formatTokens[checkStr].tokenId;
5261 pData = pData + 1;
5262 realLen = realLen + 1;
5264 pFormatA = pFormatA + formatTokens[checkStr].tokenSize;
5265 formatLeft = formatLeft - formatTokens[checkStr].tokenSize;
5266 checkStr = -1; /* Flag as found and break out of while loop */
5267 } else {
5268 checkStr++;
5272 /* Did we ever match a token? */
5273 if (checkStr != -1 && insertCopy == FALSE) {
5274 TRACE("No match - need to insert copy from %p [%p]\n", pFormatA, pStart);
5275 insertCopy = TRUE;
5276 copyFrom = pFormatA;
5277 } else if (checkStr != -1) {
5278 pFormatA = pFormatA + 1;
5283 /* Finally, if we have skipped chars, insert the copy */
5284 if (insertCopy == TRUE) {
5286 TRACE("Chars left over, so still copy %p,%p,%p\n", copyFrom, pStart, pFormatA);
5287 if ((realLen + 3) > cbTok) {
5288 HeapFree( GetProcessHeap(), 0, pFormatA );
5289 return TYPE_E_BUFFERTOOSMALL;
5291 insertCopy = FALSE;
5292 *pData = TOK_COPY;
5293 pData++;
5294 *pData = (BYTE)(copyFrom - pStart);
5295 pData++;
5296 *pData = (BYTE)(pFormatA - copyFrom);
5297 pData++;
5298 realLen = realLen + 3;
5301 /* Finally insert the terminator */
5302 if ((realLen + 1) > cbTok) {
5303 HeapFree( GetProcessHeap(), 0, pFormatA );
5304 return TYPE_E_BUFFERTOOSMALL;
5306 *pData++ = TOK_END;
5307 realLen = realLen + 1;
5309 /* Finally fill in the length */
5310 hdr->len = realLen;
5311 *pcbActual = realLen;
5313 #if 0
5314 { int i,j;
5315 for (i=0; i<realLen; i=i+0x10) {
5316 printf(" %4.4x : ", i);
5317 for (j=0; j<0x10 && (i+j < realLen); j++) {
5318 printf("%2.2x ", rgbTok[i+j]);
5320 printf("\n");
5323 #endif
5324 HeapFree( GetProcessHeap(), 0, pFormatA );
5326 return S_OK;
5329 /**********************************************************************
5330 * VarFormatFromTokens [OLEAUT32.139]
5331 * FIXME: No account of flags or iFirstDay etc
5333 HRESULT WINAPI VarFormatFromTokens(LPVARIANT varIn, LPOLESTR format,
5334 LPBYTE pbTokCur, ULONG dwFlags, BSTR *pbstrOut,
5335 LCID lcid) {
5337 FORMATHDR *hdr = (FORMATHDR *)pbTokCur;
5338 BYTE *pData = pbTokCur + sizeof (FORMATHDR);
5339 LPSTR pFormatA = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
5340 char output[BUFFER_MAX];
5341 char *pNextPos;
5342 int size, whichToken;
5343 VARIANTARG Variant;
5344 struct tm TM;
5348 TRACE("'%s', %p %lx %p only date support\n", pFormatA, pbTokCur, dwFlags, pbstrOut);
5349 TRACE("varIn:\n");
5350 dump_Variant(varIn);
5352 memset(output, 0x00, BUFFER_MAX);
5353 pNextPos = output;
5355 while (*pData != TOK_END && ((pData - pbTokCur) <= (hdr->len))) {
5357 TRACE("Output looks like : '%s'\n", output);
5359 /* Convert varient to appropriate data type */
5360 whichToken = 0;
5361 while ((formatTokens[whichToken].tokenSize != 0x00) &&
5362 (formatTokens[whichToken].tokenId != *pData)) {
5363 whichToken++;
5366 /* Use Variant local from here downwards as always correct type */
5367 if (formatTokens[whichToken].tokenSize > 0 &&
5368 formatTokens[whichToken].varTypeRequired != 0) {
5369 VariantInit( &Variant );
5370 if (Coerce( &Variant, lcid, dwFlags, varIn,
5371 formatTokens[whichToken].varTypeRequired ) != S_OK) {
5372 HeapFree( GetProcessHeap(), 0, pFormatA );
5373 return DISP_E_TYPEMISMATCH;
5374 } else if (formatTokens[whichToken].varTypeRequired == VT_DATE) {
5375 if( DateToTm( V_UNION(&Variant,date), dwFlags, &TM ) == FALSE ) {
5376 HeapFree( GetProcessHeap(), 0, pFormatA );
5377 return E_INVALIDARG;
5382 TRACE("Looking for match on token '%x'\n", *pData);
5383 switch (*pData) {
5384 case TOK_COPY:
5385 TRACE("Copy from %d for %d bytes\n", *(pData+1), *(pData+2));
5386 memcpy(pNextPos, &pFormatA[*(pData+1)], *(pData+2));
5387 pNextPos = pNextPos + *(pData+2);
5388 pData = pData + 3;
5389 break;
5391 case TOK_COLON :
5392 /* Get locale information - Time Seperator */
5393 size = GetLocaleInfoA(lcid, LOCALE_STIME, NULL, 0);
5394 GetLocaleInfoA(lcid, LOCALE_STIME, pNextPos, size);
5395 TRACE("TOK_COLON Time seperator is '%s'\n", pNextPos);
5396 pNextPos = pNextPos + size;
5397 pData = pData + 1;
5398 break;
5400 case TOK_SLASH :
5401 /* Get locale information - Date Seperator */
5402 size = GetLocaleInfoA(lcid, LOCALE_SDATE, NULL, 0);
5403 GetLocaleInfoA(lcid, LOCALE_SDATE, pNextPos, size);
5404 TRACE("TOK_COLON Time seperator is '%s'\n", pNextPos);
5405 pNextPos = pNextPos + size;
5406 pData = pData + 1;
5407 break;
5409 case TOK_d :
5410 sprintf(pNextPos, "%d", TM.tm_mday);
5411 pNextPos = pNextPos + strlen(pNextPos);
5412 pData = pData + 1;
5413 break;
5415 case TOK_dd :
5416 sprintf(pNextPos, "%2.2d", TM.tm_mday);
5417 pNextPos = pNextPos + strlen(pNextPos);
5418 pData = pData + 1;
5419 break;
5421 case TOK_w :
5422 sprintf(pNextPos, "%d", TM.tm_wday+1);
5423 pNextPos = pNextPos + strlen(pNextPos);
5424 pData = pData + 1;
5425 break;
5427 case TOK_m :
5428 sprintf(pNextPos, "%d", TM.tm_mon+1);
5429 pNextPos = pNextPos + strlen(pNextPos);
5430 pData = pData + 1;
5431 break;
5433 case TOK_mm :
5434 sprintf(pNextPos, "%2.2d", TM.tm_mon+1);
5435 pNextPos = pNextPos + strlen(pNextPos);
5436 pData = pData + 1;
5437 break;
5439 case TOK_q :
5440 sprintf(pNextPos, "%d", ((TM.tm_mon+1)/4)+1);
5441 pNextPos = pNextPos + strlen(pNextPos);
5442 pData = pData + 1;
5443 break;
5445 case TOK_y :
5446 sprintf(pNextPos, "%2.2d", TM.tm_yday+1);
5447 pNextPos = pNextPos + strlen(pNextPos);
5448 pData = pData + 1;
5449 break;
5451 case TOK_yy :
5452 sprintf(pNextPos, "%2.2d", TM.tm_year);
5453 pNextPos = pNextPos + strlen(pNextPos);
5454 pData = pData + 1;
5455 break;
5457 case TOK_yyyy :
5458 sprintf(pNextPos, "%4.4d", TM.tm_year);
5459 pNextPos = pNextPos + strlen(pNextPos);
5460 pData = pData + 1;
5461 break;
5463 case TOK_h :
5464 sprintf(pNextPos, "%d", TM.tm_hour);
5465 pNextPos = pNextPos + strlen(pNextPos);
5466 pData = pData + 1;
5467 break;
5469 case TOK_Hh :
5470 sprintf(pNextPos, "%2.2d", TM.tm_hour);
5471 pNextPos = pNextPos + strlen(pNextPos);
5472 pData = pData + 1;
5473 break;
5475 case TOK_N :
5476 sprintf(pNextPos, "%d", TM.tm_min);
5477 pNextPos = pNextPos + strlen(pNextPos);
5478 pData = pData + 1;
5479 break;
5481 case TOK_Nn :
5482 sprintf(pNextPos, "%2.2d", TM.tm_min);
5483 pNextPos = pNextPos + strlen(pNextPos);
5484 pData = pData + 1;
5485 break;
5487 case TOK_S :
5488 sprintf(pNextPos, "%d", TM.tm_sec);
5489 pNextPos = pNextPos + strlen(pNextPos);
5490 pData = pData + 1;
5491 break;
5493 case TOK_Ss :
5494 sprintf(pNextPos, "%2.2d", TM.tm_sec);
5495 pNextPos = pNextPos + strlen(pNextPos);
5496 pData = pData + 1;
5497 break;
5499 /* FIXME: To Do! */
5500 case TOK_ttttt :
5501 case TOK_AMsPM :
5502 case TOK_amspm :
5503 case TOK_AsP :
5504 case TOK_asp :
5505 case TOK_AMPM :
5506 case TOK_c :
5507 case TOK_ddd :
5508 case TOK_dddd :
5509 case TOK_ddddd :
5510 case TOK_dddddd :
5511 case TOK_ww :
5512 case TOK_mmm :
5513 case TOK_mmmm :
5514 default:
5515 FIXME("Unhandled token for VarFormat %d\n", *pData);
5516 HeapFree( GetProcessHeap(), 0, pFormatA );
5517 return E_INVALIDARG;
5522 *pbstrOut = StringDupAtoBstr( output );
5523 HeapFree( GetProcessHeap(), 0, pFormatA );
5524 return S_OK;
5527 /**********************************************************************
5528 * VarFormat [OLEAUT32.87]
5531 HRESULT WINAPI VarFormat(LPVARIANT varIn, LPOLESTR format,
5532 int firstDay, int firstWeek, ULONG dwFlags,
5533 BSTR *pbstrOut) {
5535 LPSTR pNewString = NULL;
5536 HRESULT rc = S_OK;
5538 TRACE("mostly stub! format='%s' day=%d, wk=%d, flags=%ld\n",
5539 debugstr_w(format), firstDay, firstWeek, dwFlags);
5540 TRACE("varIn:\n");
5541 dump_Variant(varIn);
5543 /* Note: Must Handle references type Variants (contain ptrs
5544 to values rather than values */
5546 /* Get format string */
5547 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
5549 /* FIXME: Handle some simple pre-definted format strings : */
5550 if (((V_VT(varIn)&VT_TYPEMASK) == VT_CY) && (lstrcmpiA(pNewString, "Currency") == 0)) {
5552 /* Can't use VarBstrFromCy as it does not put currency sign on nor decimal places */
5553 double curVal;
5556 /* Handle references type Variants (contain ptrs to values rather than values */
5557 if (V_VT(varIn)&VT_BYREF) {
5558 rc = VarR8FromCy(*(CY *)V_UNION(varIn,byref), &curVal);
5559 } else {
5560 rc = VarR8FromCy(V_UNION(varIn,cyVal), &curVal);
5563 if (rc == S_OK) {
5564 char tmpStr[BUFFER_MAX];
5565 sprintf(tmpStr, "%f", curVal);
5566 if (GetCurrencyFormatA(GetUserDefaultLCID(), dwFlags, tmpStr, NULL, pBuffer, BUFFER_MAX) == 0) {
5567 return E_FAIL;
5568 } else {
5569 *pbstrOut = StringDupAtoBstr( pBuffer );
5573 } else if ((V_VT(varIn)&VT_TYPEMASK) == VT_DATE) {
5575 /* Attempt to do proper formatting! */
5576 int firstToken = -1;
5578 rc = VarTokenizeFormatString(format, pBuffer, sizeof(pBuffer), firstDay,
5579 firstWeek, GetUserDefaultLCID(), &firstToken);
5580 if (rc==S_OK) {
5581 rc = VarFormatFromTokens(varIn, format, pBuffer, dwFlags, pbstrOut, GetUserDefaultLCID());
5584 } else if ((V_VT(varIn)&VT_TYPEMASK) == VT_R8) {
5585 if (V_VT(varIn)&VT_BYREF) {
5586 sprintf(pBuffer, "%f", *(double *)V_UNION(varIn,byref));
5587 } else {
5588 sprintf(pBuffer, "%f", V_UNION(varIn,dblVal));
5591 *pbstrOut = StringDupAtoBstr( pBuffer );
5593 } else {
5594 FIXME("VarFormat: Unsupported format %d!\n", V_VT(varIn)&VT_TYPEMASK);
5595 *pbstrOut = StringDupAtoBstr( "??" );
5598 /* Free allocated storage */
5599 HeapFree( GetProcessHeap(), 0, pNewString );
5600 TRACE("result: '%s'\n", debugstr_w(*pbstrOut));
5601 return rc;
5604 /**********************************************************************
5605 * VarCyMulI4 [OLEAUT32.304]
5606 * Multiply currency value by integer
5608 HRESULT WINAPI VarCyMulI4(CY cyIn, LONG mulBy, CY *pcyOut) {
5610 double cyVal = 0;
5611 HRESULT rc = S_OK;
5613 rc = VarR8FromCy(cyIn, &cyVal);
5614 if (rc == S_OK) {
5615 rc = VarCyFromR8((cyVal * (double) mulBy), pcyOut);
5616 TRACE("Multiply %f by %ld = %f [%ld,%lu]\n", cyVal, mulBy, (cyVal * (double) mulBy),
5617 pcyOut->s.Hi, pcyOut->s.Lo);
5619 return rc;