- VarAnd, VarCmp (Strings only), VarNot implemented.
[wine/testsucceed.git] / dlls / oleaut32 / variant.c
blob76d4195f08875ee6cb0c4ef12cac7fb0e2659622
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 size = sizeof(void*);
643 break;
644 case( VT_CY ):
645 case( VT_DISPATCH ):
646 case( VT_UNKNOWN ):
647 case( VT_DECIMAL ):
648 default:
649 FIXME("Add size information for type vt=%d\n", V_VT(parg) & VT_TYPEMASK );
650 break;
653 return size;
655 /******************************************************************************
656 * StringDupAtoBstr [INTERNAL]
659 static BSTR StringDupAtoBstr( char* strIn )
661 BSTR bstr = NULL;
662 OLECHAR* pNewString = NULL;
663 pNewString = HEAP_strdupAtoW( GetProcessHeap(), 0, strIn );
664 bstr = SysAllocString( pNewString );
665 HeapFree( GetProcessHeap(), 0, pNewString );
666 return bstr;
669 /******************************************************************************
670 * round [INTERNAL]
672 * Round the double value to the nearest integer value.
674 static double round( double d )
676 double decimals = 0.0, integerValue = 0.0, roundedValue = 0.0;
677 BOOL bEvenNumber = FALSE;
678 int nSign = 0;
680 /* Save the sign of the number
682 nSign = (d >= 0.0) ? 1 : -1;
683 d = fabs( d );
685 /* Remove the decimals.
687 integerValue = floor( d );
689 /* Set the Even flag. This is used to round the number when
690 * the decimals are exactly 1/2. If the integer part is
691 * odd the number is rounded up. If the integer part
692 * is even the number is rounded down. Using this method
693 * numbers are rounded up|down half the time.
695 bEvenNumber = (((short)fmod(integerValue, 2)) == 0) ? TRUE : FALSE;
697 /* Remove the integral part of the number.
699 decimals = d - integerValue;
701 /* Note: Ceil returns the smallest integer that is greater that x.
702 * and floor returns the largest integer that is less than or equal to x.
704 if( decimals > 0.5 )
706 /* If the decimal part is greater than 1/2
708 roundedValue = ceil( d );
710 else if( decimals < 0.5 )
712 /* If the decimal part is smaller than 1/2
714 roundedValue = floor( d );
716 else
718 /* the decimals are exactly 1/2 so round according to
719 * the bEvenNumber flag.
721 if( bEvenNumber )
723 roundedValue = floor( d );
725 else
727 roundedValue = ceil( d );
731 return roundedValue * nSign;
734 /******************************************************************************
735 * RemoveCharacterFromString [INTERNAL]
737 * Removes any of the characters in "strOfCharToRemove" from the "str" argument.
739 static void RemoveCharacterFromString( LPSTR str, LPSTR strOfCharToRemove )
741 LPSTR pNewString = NULL;
742 LPSTR strToken = NULL;
744 /* Check if we have a valid argument
746 if( str != NULL )
748 pNewString = strdup( str );
749 str[0] = '\0';
750 strToken = strtok( pNewString, strOfCharToRemove );
751 while( strToken != NULL ) {
752 strcat( str, strToken );
753 strToken = strtok( NULL, strOfCharToRemove );
755 free( pNewString );
757 return;
760 /******************************************************************************
761 * GetValidRealString [INTERNAL]
763 * Checks if the string is of proper format to be converted to a real value.
765 static BOOL IsValidRealString( LPSTR strRealString )
767 /* Real values that have a decimal point are required to either have
768 * digits before or after the decimal point. We will assume that
769 * we do not have any digits at either position. If we do encounter
770 * some we will disable this flag.
772 BOOL bDigitsRequired = TRUE;
773 /* Processed fields in the string representation of the real number.
775 BOOL bWhiteSpaceProcessed = FALSE;
776 BOOL bFirstSignProcessed = FALSE;
777 BOOL bFirstDigitsProcessed = FALSE;
778 BOOL bDecimalPointProcessed = FALSE;
779 BOOL bSecondDigitsProcessed = FALSE;
780 BOOL bExponentProcessed = FALSE;
781 BOOL bSecondSignProcessed = FALSE;
782 BOOL bThirdDigitsProcessed = FALSE;
783 /* Assume string parameter "strRealString" is valid and try to disprove it.
785 BOOL bValidRealString = TRUE;
787 /* Used to count the number of tokens in the "strRealString".
789 LPSTR strToken = NULL;
790 int nTokens = 0;
791 LPSTR pChar = NULL;
793 /* Check if we have a valid argument
795 if( strRealString == NULL )
797 bValidRealString = FALSE;
800 if( bValidRealString == TRUE )
802 /* Make sure we only have ONE token in the string.
804 strToken = strtok( strRealString, " " );
805 while( strToken != NULL ) {
806 nTokens++;
807 strToken = strtok( NULL, " " );
810 if( nTokens != 1 )
812 bValidRealString = FALSE;
817 /* Make sure this token contains only valid characters.
818 * The string argument to atof has the following form:
819 * [whitespace] [sign] [digits] [.digits] [ {d | D | e | E }[sign]digits]
820 * Whitespace consists of space and|or <TAB> characters, which are ignored.
821 * Sign is either plus '+' or minus '-'.
822 * Digits are one or more decimal digits.
823 * Note: If no digits appear before the decimal point, at least one must
824 * appear after the decimal point.
825 * The decimal digits may be followed by an exponent.
826 * An Exponent consists of an introductory letter ( D, d, E, or e) and
827 * an optionally signed decimal integer.
829 pChar = strRealString;
830 while( bValidRealString == TRUE && *pChar != '\0' )
832 switch( *pChar )
834 /* If whitespace...
836 case ' ':
837 case '\t':
838 if( bWhiteSpaceProcessed ||
839 bFirstSignProcessed ||
840 bFirstDigitsProcessed ||
841 bDecimalPointProcessed ||
842 bSecondDigitsProcessed ||
843 bExponentProcessed ||
844 bSecondSignProcessed ||
845 bThirdDigitsProcessed )
847 bValidRealString = FALSE;
849 break;
850 /* If sign...
852 case '+':
853 case '-':
854 if( bFirstSignProcessed == FALSE )
856 if( bFirstDigitsProcessed ||
857 bDecimalPointProcessed ||
858 bSecondDigitsProcessed ||
859 bExponentProcessed ||
860 bSecondSignProcessed ||
861 bThirdDigitsProcessed )
863 bValidRealString = FALSE;
865 bWhiteSpaceProcessed = TRUE;
866 bFirstSignProcessed = TRUE;
868 else if( bSecondSignProcessed == FALSE )
870 /* Note: The exponent must be present in
871 * order to accept the second sign...
873 if( bExponentProcessed == FALSE ||
874 bThirdDigitsProcessed ||
875 bDigitsRequired )
877 bValidRealString = FALSE;
879 bFirstSignProcessed = TRUE;
880 bWhiteSpaceProcessed = TRUE;
881 bFirstDigitsProcessed = TRUE;
882 bDecimalPointProcessed = TRUE;
883 bSecondDigitsProcessed = TRUE;
884 bSecondSignProcessed = TRUE;
886 break;
888 /* If decimals...
890 case '0':
891 case '1':
892 case '2':
893 case '3':
894 case '4':
895 case '5':
896 case '6':
897 case '7':
898 case '8':
899 case '9':
900 if( bFirstDigitsProcessed == FALSE )
902 if( bDecimalPointProcessed ||
903 bSecondDigitsProcessed ||
904 bExponentProcessed ||
905 bSecondSignProcessed ||
906 bThirdDigitsProcessed )
908 bValidRealString = FALSE;
910 bFirstSignProcessed = TRUE;
911 bWhiteSpaceProcessed = TRUE;
912 /* We have found some digits before the decimal point
913 * so disable the "Digits required" flag.
915 bDigitsRequired = FALSE;
917 else if( bSecondDigitsProcessed == FALSE )
919 if( bExponentProcessed ||
920 bSecondSignProcessed ||
921 bThirdDigitsProcessed )
923 bValidRealString = FALSE;
925 bFirstSignProcessed = TRUE;
926 bWhiteSpaceProcessed = TRUE;
927 bFirstDigitsProcessed = TRUE;
928 bDecimalPointProcessed = TRUE;
929 /* We have found some digits after the decimal point
930 * so disable the "Digits required" flag.
932 bDigitsRequired = FALSE;
934 else if( bThirdDigitsProcessed == FALSE )
936 /* Getting here means everything else should be processed.
937 * If we get anything else than a decimal following this
938 * digit it will be flagged by the other cases, so
939 * we do not really need to do anything in here.
942 break;
943 /* If DecimalPoint...
945 case '.':
946 if( bDecimalPointProcessed ||
947 bSecondDigitsProcessed ||
948 bExponentProcessed ||
949 bSecondSignProcessed ||
950 bThirdDigitsProcessed )
952 bValidRealString = FALSE;
954 bFirstSignProcessed = TRUE;
955 bWhiteSpaceProcessed = TRUE;
956 bFirstDigitsProcessed = TRUE;
957 bDecimalPointProcessed = TRUE;
958 break;
959 /* If Exponent...
961 case 'e':
962 case 'E':
963 case 'd':
964 case 'D':
965 if( bExponentProcessed ||
966 bSecondSignProcessed ||
967 bThirdDigitsProcessed ||
968 bDigitsRequired )
970 bValidRealString = FALSE;
972 bFirstSignProcessed = TRUE;
973 bWhiteSpaceProcessed = TRUE;
974 bFirstDigitsProcessed = TRUE;
975 bDecimalPointProcessed = TRUE;
976 bSecondDigitsProcessed = TRUE;
977 bExponentProcessed = TRUE;
978 break;
979 default:
980 bValidRealString = FALSE;
981 break;
983 /* Process next character.
985 pChar++;
988 /* If the required digits were not present we have an invalid
989 * string representation of a real number.
991 if( bDigitsRequired == TRUE )
993 bValidRealString = FALSE;
996 return bValidRealString;
1000 /******************************************************************************
1001 * Coerce [INTERNAL]
1003 * This function dispatches execution to the proper conversion API
1004 * to do the necessary coercion.
1006 * FIXME: Passing down dwFlags to the conversion functions is wrong, this
1007 * is a different flagmask. Check MSDN.
1009 static HRESULT Coerce( VARIANTARG* pd, LCID lcid, ULONG dwFlags, VARIANTARG* ps, VARTYPE vt )
1011 HRESULT res = S_OK;
1012 unsigned short vtFrom = 0;
1013 vtFrom = V_VT(ps) & VT_TYPEMASK;
1016 /* Note: Since "long" and "int" values both have 4 bytes and are
1017 * both signed integers "int" will be treated as "long" in the
1018 * following code.
1019 * The same goes for their unsigned versions.
1022 /* Trivial Case: If the coercion is from two types that are
1023 * identical then we can blindly copy from one argument to another.*/
1024 if ((vt==vtFrom))
1026 return VariantCopy(pd,ps);
1029 /* Cases requiring thought*/
1030 switch( vt )
1033 case( VT_EMPTY ):
1034 res = VariantClear( pd );
1035 break;
1036 case( VT_NULL ):
1037 res = VariantClear( pd );
1038 if( res == S_OK )
1040 V_VT(pd) = VT_NULL;
1042 break;
1043 case( VT_I1 ):
1044 switch( vtFrom )
1046 case( VT_I1 ):
1047 res = VariantCopy( pd, ps );
1048 break;
1049 case( VT_I2 ):
1050 res = VarI1FromI2( V_UNION(ps,iVal), &V_UNION(pd,cVal) );
1051 break;
1052 case( VT_INT ):
1053 case( VT_I4 ):
1054 res = VarI1FromI4( V_UNION(ps,lVal), &V_UNION(pd,cVal) );
1055 break;
1056 case( VT_UI1 ):
1057 res = VarI1FromUI1( V_UNION(ps,bVal), &V_UNION(pd,cVal) );
1058 break;
1059 case( VT_UI2 ):
1060 res = VarI1FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,cVal) );
1061 break;
1062 case( VT_UINT ):
1063 case( VT_UI4 ):
1064 res = VarI1FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,cVal) );
1065 break;
1066 case( VT_R4 ):
1067 res = VarI1FromR4( V_UNION(ps,fltVal), &V_UNION(pd,cVal) );
1068 break;
1069 case( VT_R8 ):
1070 res = VarI1FromR8( V_UNION(ps,dblVal), &V_UNION(pd,cVal) );
1071 break;
1072 case( VT_DATE ):
1073 res = VarI1FromDate( V_UNION(ps,date), &V_UNION(pd,cVal) );
1074 break;
1075 case( VT_BOOL ):
1076 res = VarI1FromBool( V_UNION(ps,boolVal), &V_UNION(pd,cVal) );
1077 break;
1078 case( VT_BSTR ):
1079 res = VarI1FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,cVal) );
1080 break;
1081 case( VT_CY ):
1082 res = VarI1FromCy( V_UNION(ps,cyVal), &V_UNION(pd,cVal) );
1083 break;
1084 case( VT_DISPATCH ):
1085 /*res = VarI1FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,cVal) );*/
1086 case( VT_DECIMAL ):
1087 /*res = VarI1FromDec( V_UNION(ps,decVal), &V_UNION(pd,cVal) );*/
1088 case( VT_UNKNOWN ):
1089 default:
1090 res = DISP_E_TYPEMISMATCH;
1091 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1092 break;
1094 break;
1096 case( VT_I2 ):
1097 switch( vtFrom )
1099 case( VT_I1 ):
1100 res = VarI2FromI1( V_UNION(ps,cVal), &V_UNION(pd,iVal) );
1101 break;
1102 case( VT_I2 ):
1103 res = VariantCopy( pd, ps );
1104 break;
1105 case( VT_INT ):
1106 case( VT_I4 ):
1107 res = VarI2FromI4( V_UNION(ps,lVal), &V_UNION(pd,iVal) );
1108 break;
1109 case( VT_UI1 ):
1110 res = VarI2FromUI1( V_UNION(ps,bVal), &V_UNION(pd,iVal) );
1111 break;
1112 case( VT_UI2 ):
1113 res = VarI2FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,iVal) );
1114 break;
1115 case( VT_UINT ):
1116 case( VT_UI4 ):
1117 res = VarI2FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,iVal) );
1118 break;
1119 case( VT_R4 ):
1120 res = VarI2FromR4( V_UNION(ps,fltVal), &V_UNION(pd,iVal) );
1121 break;
1122 case( VT_R8 ):
1123 res = VarI2FromR8( V_UNION(ps,dblVal), &V_UNION(pd,iVal) );
1124 break;
1125 case( VT_DATE ):
1126 res = VarI2FromDate( V_UNION(ps,date), &V_UNION(pd,iVal) );
1127 break;
1128 case( VT_BOOL ):
1129 res = VarI2FromBool( V_UNION(ps,boolVal), &V_UNION(pd,iVal) );
1130 break;
1131 case( VT_BSTR ):
1132 res = VarI2FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,iVal) );
1133 break;
1134 case( VT_CY ):
1135 res = VarI2FromCy( V_UNION(ps,cyVal), &V_UNION(pd,iVal) );
1136 break;
1137 case( VT_DISPATCH ):
1138 /*res = VarI2FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,iVal) );*/
1139 case( VT_DECIMAL ):
1140 /*res = VarI2FromDec( V_UNION(ps,deiVal), &V_UNION(pd,iVal) );*/
1141 case( VT_UNKNOWN ):
1142 default:
1143 res = DISP_E_TYPEMISMATCH;
1144 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1145 break;
1147 break;
1149 case( VT_INT ):
1150 case( VT_I4 ):
1151 switch( vtFrom )
1153 case( VT_EMPTY ):
1154 V_UNION(pd,lVal) = 0;
1155 res = S_OK;
1156 break;
1157 case( VT_I1 ):
1158 res = VarI4FromI1( V_UNION(ps,cVal), &V_UNION(pd,lVal) );
1159 break;
1160 case( VT_I2 ):
1161 res = VarI4FromI2( V_UNION(ps,iVal), &V_UNION(pd,lVal) );
1162 break;
1163 case( VT_INT ):
1164 case( VT_I4 ):
1165 res = VariantCopy( pd, ps );
1166 break;
1167 case( VT_UI1 ):
1168 res = VarI4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,lVal) );
1169 break;
1170 case( VT_UI2 ):
1171 res = VarI4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,lVal) );
1172 break;
1173 case( VT_UINT ):
1174 case( VT_UI4 ):
1175 res = VarI4FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,lVal) );
1176 break;
1177 case( VT_R4 ):
1178 res = VarI4FromR4( V_UNION(ps,fltVal), &V_UNION(pd,lVal) );
1179 break;
1180 case( VT_R8 ):
1181 res = VarI4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,lVal) );
1182 break;
1183 case( VT_DATE ):
1184 res = VarI4FromDate( V_UNION(ps,date), &V_UNION(pd,lVal) );
1185 break;
1186 case( VT_BOOL ):
1187 res = VarI4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,lVal) );
1188 break;
1189 case( VT_BSTR ):
1190 res = VarI4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,lVal) );
1191 break;
1192 case( VT_CY ):
1193 res = VarI4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,lVal) );
1194 break;
1195 case( VT_DISPATCH ):
1196 /*res = VarI4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,lVal) );*/
1197 case( VT_DECIMAL ):
1198 /*res = VarI4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,lVal) );*/
1199 case( VT_UNKNOWN ):
1200 default:
1201 res = DISP_E_TYPEMISMATCH;
1202 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1203 break;
1205 break;
1207 case( VT_UI1 ):
1208 switch( vtFrom )
1210 case( VT_I1 ):
1211 res = VarUI1FromI1( V_UNION(ps,cVal), &V_UNION(pd,bVal) );
1212 break;
1213 case( VT_I2 ):
1214 res = VarUI1FromI2( V_UNION(ps,iVal), &V_UNION(pd,bVal) );
1215 break;
1216 case( VT_INT ):
1217 case( VT_I4 ):
1218 res = VarUI1FromI4( V_UNION(ps,lVal), &V_UNION(pd,bVal) );
1219 break;
1220 case( VT_UI1 ):
1221 res = VariantCopy( pd, ps );
1222 break;
1223 case( VT_UI2 ):
1224 res = VarUI1FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,bVal) );
1225 break;
1226 case( VT_UINT ):
1227 case( VT_UI4 ):
1228 res = VarUI1FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,bVal) );
1229 break;
1230 case( VT_R4 ):
1231 res = VarUI1FromR4( V_UNION(ps,fltVal), &V_UNION(pd,bVal) );
1232 break;
1233 case( VT_R8 ):
1234 res = VarUI1FromR8( V_UNION(ps,dblVal), &V_UNION(pd,bVal) );
1235 break;
1236 case( VT_DATE ):
1237 res = VarUI1FromDate( V_UNION(ps,date), &V_UNION(pd,bVal) );
1238 break;
1239 case( VT_BOOL ):
1240 res = VarUI1FromBool( V_UNION(ps,boolVal), &V_UNION(pd,bVal) );
1241 break;
1242 case( VT_BSTR ):
1243 res = VarUI1FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,bVal) );
1244 break;
1245 case( VT_CY ):
1246 res = VarUI1FromCy( V_UNION(ps,cyVal), &V_UNION(pd,bVal) );
1247 break;
1248 case( VT_DISPATCH ):
1249 /*res = VarUI1FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,bVal) );*/
1250 case( VT_DECIMAL ):
1251 /*res = VarUI1FromDec( V_UNION(ps,deiVal), &V_UNION(pd,bVal) );*/
1252 case( VT_UNKNOWN ):
1253 default:
1254 res = DISP_E_TYPEMISMATCH;
1255 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1256 break;
1258 break;
1260 case( VT_UI2 ):
1261 switch( vtFrom )
1263 case( VT_I1 ):
1264 res = VarUI2FromI1( V_UNION(ps,cVal), &V_UNION(pd,uiVal) );
1265 break;
1266 case( VT_I2 ):
1267 res = VarUI2FromI2( V_UNION(ps,iVal), &V_UNION(pd,uiVal) );
1268 break;
1269 case( VT_INT ):
1270 case( VT_I4 ):
1271 res = VarUI2FromI4( V_UNION(ps,lVal), &V_UNION(pd,uiVal) );
1272 break;
1273 case( VT_UI1 ):
1274 res = VarUI2FromUI1( V_UNION(ps,bVal), &V_UNION(pd,uiVal) );
1275 break;
1276 case( VT_UI2 ):
1277 res = VariantCopy( pd, ps );
1278 break;
1279 case( VT_UINT ):
1280 case( VT_UI4 ):
1281 res = VarUI2FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,uiVal) );
1282 break;
1283 case( VT_R4 ):
1284 res = VarUI2FromR4( V_UNION(ps,fltVal), &V_UNION(pd,uiVal) );
1285 break;
1286 case( VT_R8 ):
1287 res = VarUI2FromR8( V_UNION(ps,dblVal), &V_UNION(pd,uiVal) );
1288 break;
1289 case( VT_DATE ):
1290 res = VarUI2FromDate( V_UNION(ps,date), &V_UNION(pd,uiVal) );
1291 break;
1292 case( VT_BOOL ):
1293 res = VarUI2FromBool( V_UNION(ps,boolVal), &V_UNION(pd,uiVal) );
1294 break;
1295 case( VT_BSTR ):
1296 res = VarUI2FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,uiVal) );
1297 break;
1298 case( VT_CY ):
1299 res = VarUI2FromCy( V_UNION(ps,cyVal), &V_UNION(pd,uiVal) );
1300 break;
1301 case( VT_DISPATCH ):
1302 /*res = VarUI2FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,uiVal) );*/
1303 case( VT_DECIMAL ):
1304 /*res = VarUI2FromDec( V_UNION(ps,deiVal), &V_UNION(pd,uiVal) );*/
1305 case( VT_UNKNOWN ):
1306 default:
1307 res = DISP_E_TYPEMISMATCH;
1308 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1309 break;
1311 break;
1313 case( VT_UINT ):
1314 case( VT_UI4 ):
1315 switch( vtFrom )
1317 case( VT_I1 ):
1318 res = VarUI4FromI1( V_UNION(ps,cVal), &V_UNION(pd,ulVal) );
1319 break;
1320 case( VT_I2 ):
1321 res = VarUI4FromI2( V_UNION(ps,iVal), &V_UNION(pd,ulVal) );
1322 break;
1323 case( VT_INT ):
1324 case( VT_I4 ):
1325 res = VarUI4FromI4( V_UNION(ps,lVal), &V_UNION(pd,ulVal) );
1326 break;
1327 case( VT_UI1 ):
1328 res = VarUI4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,ulVal) );
1329 break;
1330 case( VT_UI2 ):
1331 res = VarUI4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,ulVal) );
1332 break;
1333 case( VT_UI4 ):
1334 res = VariantCopy( pd, ps );
1335 break;
1336 case( VT_R4 ):
1337 res = VarUI4FromR4( V_UNION(ps,fltVal), &V_UNION(pd,ulVal) );
1338 break;
1339 case( VT_R8 ):
1340 res = VarUI4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,ulVal) );
1341 break;
1342 case( VT_DATE ):
1343 res = VarUI4FromDate( V_UNION(ps,date), &V_UNION(pd,ulVal) );
1344 break;
1345 case( VT_BOOL ):
1346 res = VarUI4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,ulVal) );
1347 break;
1348 case( VT_BSTR ):
1349 res = VarUI4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,ulVal) );
1350 break;
1351 case( VT_CY ):
1352 res = VarUI4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,ulVal) );
1353 break;
1354 case( VT_DISPATCH ):
1355 /*res = VarUI4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,ulVal) );*/
1356 case( VT_DECIMAL ):
1357 /*res = VarUI4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,ulVal) );*/
1358 case( VT_UNKNOWN ):
1359 default:
1360 res = DISP_E_TYPEMISMATCH;
1361 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1362 break;
1364 break;
1366 case( VT_R4 ):
1367 switch( vtFrom )
1369 case( VT_I1 ):
1370 res = VarR4FromI1( V_UNION(ps,cVal), &V_UNION(pd,fltVal) );
1371 break;
1372 case( VT_I2 ):
1373 res = VarR4FromI2( V_UNION(ps,iVal), &V_UNION(pd,fltVal) );
1374 break;
1375 case( VT_INT ):
1376 case( VT_I4 ):
1377 res = VarR4FromI4( V_UNION(ps,lVal), &V_UNION(pd,fltVal) );
1378 break;
1379 case( VT_UI1 ):
1380 res = VarR4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,fltVal) );
1381 break;
1382 case( VT_UI2 ):
1383 res = VarR4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,fltVal) );
1384 break;
1385 case( VT_UINT ):
1386 case( VT_UI4 ):
1387 res = VarR4FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,fltVal) );
1388 break;
1389 case( VT_R4 ):
1390 res = VariantCopy( pd, ps );
1391 break;
1392 case( VT_R8 ):
1393 res = VarR4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,fltVal) );
1394 break;
1395 case( VT_DATE ):
1396 res = VarR4FromDate( V_UNION(ps,date), &V_UNION(pd,fltVal) );
1397 break;
1398 case( VT_BOOL ):
1399 res = VarR4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,fltVal) );
1400 break;
1401 case( VT_BSTR ):
1402 res = VarR4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,fltVal) );
1403 break;
1404 case( VT_CY ):
1405 res = VarR4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,fltVal) );
1406 break;
1407 case( VT_DISPATCH ):
1408 /*res = VarR4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,fltVal) );*/
1409 case( VT_DECIMAL ):
1410 /*res = VarR4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,fltVal) );*/
1411 case( VT_UNKNOWN ):
1412 default:
1413 res = DISP_E_TYPEMISMATCH;
1414 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1415 break;
1417 break;
1419 case( VT_R8 ):
1420 switch( vtFrom )
1422 case( VT_I1 ):
1423 res = VarR8FromI1( V_UNION(ps,cVal), &V_UNION(pd,dblVal) );
1424 break;
1425 case( VT_I2 ):
1426 res = VarR8FromI2( V_UNION(ps,iVal), &V_UNION(pd,dblVal) );
1427 break;
1428 case( VT_INT ):
1429 case( VT_I4 ):
1430 res = VarR8FromI4( V_UNION(ps,lVal), &V_UNION(pd,dblVal) );
1431 break;
1432 case( VT_UI1 ):
1433 res = VarR8FromUI1( V_UNION(ps,bVal), &V_UNION(pd,dblVal) );
1434 break;
1435 case( VT_UI2 ):
1436 res = VarR8FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,dblVal) );
1437 break;
1438 case( VT_UINT ):
1439 case( VT_UI4 ):
1440 res = VarR8FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,dblVal) );
1441 break;
1442 case( VT_R4 ):
1443 res = VarR8FromR4( V_UNION(ps,fltVal), &V_UNION(pd,dblVal) );
1444 break;
1445 case( VT_R8 ):
1446 res = VariantCopy( pd, ps );
1447 break;
1448 case( VT_DATE ):
1449 res = VarR8FromDate( V_UNION(ps,date), &V_UNION(pd,dblVal) );
1450 break;
1451 case( VT_BOOL ):
1452 res = VarR8FromBool( V_UNION(ps,boolVal), &V_UNION(pd,dblVal) );
1453 break;
1454 case( VT_BSTR ):
1455 res = VarR8FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,dblVal) );
1456 break;
1457 case( VT_CY ):
1458 res = VarR8FromCy( V_UNION(ps,cyVal), &V_UNION(pd,dblVal) );
1459 break;
1460 case( VT_DISPATCH ):
1461 /*res = VarR8FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,dblVal) );*/
1462 case( VT_DECIMAL ):
1463 /*res = VarR8FromDec( V_UNION(ps,deiVal), &V_UNION(pd,dblVal) );*/
1464 case( VT_UNKNOWN ):
1465 default:
1466 res = DISP_E_TYPEMISMATCH;
1467 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1468 break;
1470 break;
1472 case( VT_DATE ):
1473 switch( vtFrom )
1475 case( VT_I1 ):
1476 res = VarDateFromI1( V_UNION(ps,cVal), &V_UNION(pd,date) );
1477 break;
1478 case( VT_I2 ):
1479 res = VarDateFromI2( V_UNION(ps,iVal), &V_UNION(pd,date) );
1480 break;
1481 case( VT_INT ):
1482 res = VarDateFromInt( V_UNION(ps,intVal), &V_UNION(pd,date) );
1483 break;
1484 case( VT_I4 ):
1485 res = VarDateFromI4( V_UNION(ps,lVal), &V_UNION(pd,date) );
1486 break;
1487 case( VT_UI1 ):
1488 res = VarDateFromUI1( V_UNION(ps,bVal), &V_UNION(pd,date) );
1489 break;
1490 case( VT_UI2 ):
1491 res = VarDateFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,date) );
1492 break;
1493 case( VT_UINT ):
1494 res = VarDateFromUint( V_UNION(ps,uintVal), &V_UNION(pd,date) );
1495 break;
1496 case( VT_UI4 ):
1497 res = VarDateFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,date) );
1498 break;
1499 case( VT_R4 ):
1500 res = VarDateFromR4( V_UNION(ps,fltVal), &V_UNION(pd,date) );
1501 break;
1502 case( VT_R8 ):
1503 res = VarDateFromR8( V_UNION(ps,dblVal), &V_UNION(pd,date) );
1504 break;
1505 case( VT_DATE ):
1506 res = VariantCopy( pd, ps );
1507 break;
1508 case( VT_BOOL ):
1509 res = VarDateFromBool( V_UNION(ps,boolVal), &V_UNION(pd,date) );
1510 break;
1511 case( VT_BSTR ):
1512 res = VarDateFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,date) );
1513 break;
1514 case( VT_CY ):
1515 res = VarDateFromCy( V_UNION(ps,cyVal), &V_UNION(pd,date) );
1516 break;
1517 case( VT_DISPATCH ):
1518 /*res = VarDateFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,date) );*/
1519 case( VT_DECIMAL ):
1520 /*res = VarDateFromDec( V_UNION(ps,deiVal), &V_UNION(pd,date) );*/
1521 case( VT_UNKNOWN ):
1522 default:
1523 res = DISP_E_TYPEMISMATCH;
1524 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1525 break;
1527 break;
1529 case( VT_BOOL ):
1530 switch( vtFrom )
1532 case( VT_EMPTY ):
1533 res = S_OK;
1534 V_UNION(pd,boolVal) = VARIANT_FALSE;
1535 break;
1536 case( VT_I1 ):
1537 res = VarBoolFromI1( V_UNION(ps,cVal), &V_UNION(pd,boolVal) );
1538 break;
1539 case( VT_I2 ):
1540 res = VarBoolFromI2( V_UNION(ps,iVal), &V_UNION(pd,boolVal) );
1541 break;
1542 case( VT_INT ):
1543 res = VarBoolFromInt( V_UNION(ps,intVal), &V_UNION(pd,boolVal) );
1544 break;
1545 case( VT_I4 ):
1546 res = VarBoolFromI4( V_UNION(ps,lVal), &V_UNION(pd,boolVal) );
1547 break;
1548 case( VT_UI1 ):
1549 res = VarBoolFromUI1( V_UNION(ps,bVal), &V_UNION(pd,boolVal) );
1550 break;
1551 case( VT_UI2 ):
1552 res = VarBoolFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,boolVal) );
1553 break;
1554 case( VT_UINT ):
1555 res = VarBoolFromUint( V_UNION(ps,uintVal), &V_UNION(pd,boolVal) );
1556 break;
1557 case( VT_UI4 ):
1558 res = VarBoolFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,boolVal) );
1559 break;
1560 case( VT_R4 ):
1561 res = VarBoolFromR4( V_UNION(ps,fltVal), &V_UNION(pd,boolVal) );
1562 break;
1563 case( VT_R8 ):
1564 res = VarBoolFromR8( V_UNION(ps,dblVal), &V_UNION(pd,boolVal) );
1565 break;
1566 case( VT_DATE ):
1567 res = VarBoolFromDate( V_UNION(ps,date), &V_UNION(pd,boolVal) );
1568 break;
1569 case( VT_BOOL ):
1570 res = VariantCopy( pd, ps );
1571 break;
1572 case( VT_BSTR ):
1573 res = VarBoolFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,boolVal) );
1574 break;
1575 case( VT_CY ):
1576 res = VarBoolFromCy( V_UNION(ps,cyVal), &V_UNION(pd,boolVal) );
1577 break;
1578 case( VT_DISPATCH ):
1579 /*res = VarBoolFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,boolVal) );*/
1580 case( VT_DECIMAL ):
1581 /*res = VarBoolFromDec( V_UNION(ps,deiVal), &V_UNION(pd,boolVal) );*/
1582 case( VT_UNKNOWN ):
1583 default:
1584 res = DISP_E_TYPEMISMATCH;
1585 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1586 break;
1588 break;
1590 case( VT_BSTR ):
1591 switch( vtFrom )
1593 case( VT_EMPTY ):
1594 if ((V_UNION(pd,bstrVal) = SysAllocStringLen(NULL, 0)))
1595 res = S_OK;
1596 else
1597 res = E_OUTOFMEMORY;
1598 break;
1599 case( VT_I1 ):
1600 res = VarBstrFromI1( V_UNION(ps,cVal), lcid, 0, &V_UNION(pd,bstrVal) );
1601 break;
1602 case( VT_I2 ):
1603 res = VarBstrFromI2( V_UNION(ps,iVal), lcid, 0, &V_UNION(pd,bstrVal) );
1604 break;
1605 case( VT_INT ):
1606 res = VarBstrFromInt( V_UNION(ps,intVal), lcid, 0, &V_UNION(pd,bstrVal) );
1607 break;
1608 case( VT_I4 ):
1609 res = VarBstrFromI4( V_UNION(ps,lVal), lcid, 0, &V_UNION(pd,bstrVal) );
1610 break;
1611 case( VT_UI1 ):
1612 res = VarBstrFromUI1( V_UNION(ps,bVal), lcid, 0, &V_UNION(pd,bstrVal) );
1613 break;
1614 case( VT_UI2 ):
1615 res = VarBstrFromUI2( V_UNION(ps,uiVal), lcid, 0, &V_UNION(pd,bstrVal) );
1616 break;
1617 case( VT_UINT ):
1618 res = VarBstrFromUint( V_UNION(ps,uintVal), lcid, 0, &V_UNION(pd,bstrVal) );
1619 break;
1620 case( VT_UI4 ):
1621 res = VarBstrFromUI4( V_UNION(ps,ulVal), lcid, 0, &V_UNION(pd,bstrVal) );
1622 break;
1623 case( VT_R4 ):
1624 res = VarBstrFromR4( V_UNION(ps,fltVal), lcid, 0, &V_UNION(pd,bstrVal) );
1625 break;
1626 case( VT_R8 ):
1627 res = VarBstrFromR8( V_UNION(ps,dblVal), lcid, 0, &V_UNION(pd,bstrVal) );
1628 break;
1629 case( VT_DATE ):
1630 res = VarBstrFromDate( V_UNION(ps,date), lcid, 0, &V_UNION(pd,bstrVal) );
1631 break;
1632 case( VT_BOOL ):
1633 res = VarBstrFromBool( V_UNION(ps,boolVal), lcid, 0, &V_UNION(pd,bstrVal) );
1634 break;
1635 case( VT_BSTR ):
1636 res = VariantCopy( pd, ps );
1637 break;
1638 case( VT_CY ):
1639 res = VarBstrFromCy( V_UNION(ps,cyVal), lcid, 0, &V_UNION(pd,bstrVal) );
1640 break;
1641 case( VT_DISPATCH ):
1642 /*res = VarBstrFromDisp( V_UNION(ps,pdispVal), lcid, 0, &(pd,bstrVal) );*/
1643 case( VT_DECIMAL ):
1644 /*res = VarBstrFromDec( V_UNION(ps,deiVal), lcid, 0, &(pd,bstrVal) );*/
1645 case( VT_UNKNOWN ):
1646 default:
1647 res = DISP_E_TYPEMISMATCH;
1648 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1649 break;
1651 break;
1653 case( VT_CY ):
1654 switch( vtFrom )
1656 case( VT_I1 ):
1657 res = VarCyFromI1( V_UNION(ps,cVal), &V_UNION(pd,cyVal) );
1658 break;
1659 case( VT_I2 ):
1660 res = VarCyFromI2( V_UNION(ps,iVal), &V_UNION(pd,cyVal) );
1661 break;
1662 case( VT_INT ):
1663 res = VarCyFromInt( V_UNION(ps,intVal), &V_UNION(pd,cyVal) );
1664 break;
1665 case( VT_I4 ):
1666 res = VarCyFromI4( V_UNION(ps,lVal), &V_UNION(pd,cyVal) );
1667 break;
1668 case( VT_UI1 ):
1669 res = VarCyFromUI1( V_UNION(ps,bVal), &V_UNION(pd,cyVal) );
1670 break;
1671 case( VT_UI2 ):
1672 res = VarCyFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,cyVal) );
1673 break;
1674 case( VT_UINT ):
1675 res = VarCyFromUint( V_UNION(ps,uintVal), &V_UNION(pd,cyVal) );
1676 break;
1677 case( VT_UI4 ):
1678 res = VarCyFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,cyVal) );
1679 break;
1680 case( VT_R4 ):
1681 res = VarCyFromR4( V_UNION(ps,fltVal), &V_UNION(pd,cyVal) );
1682 break;
1683 case( VT_R8 ):
1684 res = VarCyFromR8( V_UNION(ps,dblVal), &V_UNION(pd,cyVal) );
1685 break;
1686 case( VT_DATE ):
1687 res = VarCyFromDate( V_UNION(ps,date), &V_UNION(pd,cyVal) );
1688 break;
1689 case( VT_BOOL ):
1690 res = VarCyFromBool( V_UNION(ps,date), &V_UNION(pd,cyVal) );
1691 break;
1692 case( VT_CY ):
1693 res = VariantCopy( pd, ps );
1694 break;
1695 case( VT_BSTR ):
1696 res = VarCyFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,cyVal) );
1697 break;
1698 case( VT_DISPATCH ):
1699 /*res = VarCyFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,cyVal) );*/
1700 case( VT_DECIMAL ):
1701 /*res = VarCyFromDec( V_UNION(ps,deiVal), &V_UNION(pd,cyVal) );*/
1702 break;
1703 case( VT_UNKNOWN ):
1704 default:
1705 res = DISP_E_TYPEMISMATCH;
1706 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1707 break;
1709 break;
1711 case( VT_UNKNOWN ):
1712 if (vtFrom == VT_DISPATCH)
1714 res = IDispatch_QueryInterface(V_DISPATCH(ps), &IID_IUnknown, (LPVOID*)&V_UNKNOWN(pd));
1716 else
1718 res = DISP_E_TYPEMISMATCH;
1719 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1721 break;
1723 default:
1724 res = DISP_E_TYPEMISMATCH;
1725 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1726 break;
1729 return res;
1732 /******************************************************************************
1733 * ValidateVtRange [INTERNAL]
1735 * Used internally by the hi-level Variant API to determine
1736 * if the vartypes are valid.
1738 static HRESULT WINAPI ValidateVtRange( VARTYPE vt )
1740 /* if by value we must make sure it is in the
1741 * range of the valid types.
1743 if( ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1745 return DISP_E_BADVARTYPE;
1747 return S_OK;
1751 /******************************************************************************
1752 * ValidateVartype [INTERNAL]
1754 * Used internally by the hi-level Variant API to determine
1755 * if the vartypes are valid.
1757 static HRESULT WINAPI ValidateVariantType( VARTYPE vt )
1759 HRESULT res = S_OK;
1761 /* check if we have a valid argument.
1763 if( vt & VT_BYREF )
1765 /* if by reference check that the type is in
1766 * the valid range and that it is not of empty or null type
1768 if( ( vt & VT_TYPEMASK ) == VT_EMPTY ||
1769 ( vt & VT_TYPEMASK ) == VT_NULL ||
1770 ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1772 res = DISP_E_BADVARTYPE;
1776 else
1778 res = ValidateVtRange( vt );
1781 return res;
1784 /******************************************************************************
1785 * ValidateVt [INTERNAL]
1787 * Used internally by the hi-level Variant API to determine
1788 * if the vartypes are valid.
1790 static HRESULT WINAPI ValidateVt( VARTYPE vt )
1792 HRESULT res = S_OK;
1794 /* check if we have a valid argument.
1796 if( vt & VT_BYREF )
1798 /* if by reference check that the type is in
1799 * the valid range and that it is not of empty or null type
1801 if( ( vt & VT_TYPEMASK ) == VT_EMPTY ||
1802 ( vt & VT_TYPEMASK ) == VT_NULL ||
1803 ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1805 res = DISP_E_BADVARTYPE;
1809 else
1811 res = ValidateVtRange( vt );
1814 return res;
1821 /******************************************************************************
1822 * VariantInit [OLEAUT32.8]
1824 * Initializes the Variant. Unlike VariantClear it does not interpret
1825 * the current contents of the Variant.
1827 void WINAPI VariantInit(VARIANTARG* pvarg)
1829 TRACE("(%p)\n",pvarg);
1831 memset(pvarg, 0, sizeof (VARIANTARG));
1832 V_VT(pvarg) = VT_EMPTY;
1834 return;
1837 /******************************************************************************
1838 * VariantClear [OLEAUT32.9]
1840 * This function clears the VARIANT by setting the vt field to VT_EMPTY. It also
1841 * sets the wReservedX field to 0. The current contents of the VARIANT are
1842 * freed. If the vt is VT_BSTR the string is freed. If VT_DISPATCH the object is
1843 * released. If VT_ARRAY the array is freed.
1845 HRESULT WINAPI VariantClear(VARIANTARG* pvarg)
1847 HRESULT res = S_OK;
1848 TRACE("(%p)\n",pvarg);
1850 res = ValidateVariantType( V_VT(pvarg) );
1851 if( res == S_OK )
1853 if( !( V_VT(pvarg) & VT_BYREF ) )
1856 * The VT_ARRAY flag is a special case of a safe array.
1858 if ( (V_VT(pvarg) & VT_ARRAY) != 0)
1860 SafeArrayDestroy(V_UNION(pvarg,parray));
1862 else
1864 switch( V_VT(pvarg) & VT_TYPEMASK )
1866 case( VT_BSTR ):
1867 SysFreeString( V_UNION(pvarg,bstrVal) );
1868 break;
1869 case( VT_DISPATCH ):
1870 if(V_UNION(pvarg,pdispVal)!=NULL)
1871 ICOM_CALL(Release,V_UNION(pvarg,pdispVal));
1872 break;
1873 case( VT_VARIANT ):
1874 VariantClear(V_UNION(pvarg,pvarVal));
1875 break;
1876 case( VT_UNKNOWN ):
1877 if(V_UNION(pvarg,punkVal)!=NULL)
1878 ICOM_CALL(Release,V_UNION(pvarg,punkVal));
1879 break;
1880 case( VT_SAFEARRAY ):
1881 SafeArrayDestroy(V_UNION(pvarg,parray));
1882 break;
1883 default:
1884 break;
1890 * Empty all the fields and mark the type as empty.
1892 memset(pvarg, 0, sizeof (VARIANTARG));
1893 V_VT(pvarg) = VT_EMPTY;
1896 return res;
1899 /******************************************************************************
1900 * VariantCopy [OLEAUT32.10]
1902 * Frees up the designation variant and makes a copy of the source.
1904 HRESULT WINAPI VariantCopy(VARIANTARG* pvargDest, VARIANTARG* pvargSrc)
1906 HRESULT res = S_OK;
1908 TRACE("(%p, %p), vt=%d\n", pvargDest, pvargSrc, V_VT(pvargSrc));
1910 res = ValidateVariantType( V_VT(pvargSrc) );
1912 /* If the pointer are to the same variant we don't need
1913 * to do anything.
1915 if( pvargDest != pvargSrc && res == S_OK )
1917 res = VariantClear( pvargDest );
1919 if( res == S_OK )
1921 if( V_VT(pvargSrc) & VT_BYREF )
1923 /* In the case of byreference we only need
1924 * to copy the pointer.
1926 pvargDest->n1.n2.n3 = pvargSrc->n1.n2.n3;
1927 V_VT(pvargDest) = V_VT(pvargSrc);
1929 else
1932 * The VT_ARRAY flag is another way to designate a safe array.
1934 if (V_VT(pvargSrc) & VT_ARRAY)
1936 SafeArrayCopy(V_UNION(pvargSrc,parray), &V_UNION(pvargDest,parray));
1938 else
1940 /* In the case of by value we need to
1941 * copy the actual value. In the case of
1942 * VT_BSTR a copy of the string is made,
1943 * if VT_DISPATCH or VT_IUNKNOWN AddRef is
1944 * called to increment the object's reference count.
1946 switch( V_VT(pvargSrc) & VT_TYPEMASK )
1948 case( VT_BSTR ):
1949 V_UNION(pvargDest,bstrVal) = SYSDUPSTRING( V_UNION(pvargSrc,bstrVal) );
1950 break;
1951 case( VT_DISPATCH ):
1952 V_UNION(pvargDest,pdispVal) = V_UNION(pvargSrc,pdispVal);
1953 if (V_UNION(pvargDest,pdispVal)!=NULL)
1954 ICOM_CALL(AddRef,V_UNION(pvargDest,pdispVal));
1955 break;
1956 case( VT_VARIANT ):
1957 VariantCopy(V_UNION(pvargDest,pvarVal),V_UNION(pvargSrc,pvarVal));
1958 break;
1959 case( VT_UNKNOWN ):
1960 V_UNION(pvargDest,punkVal) = V_UNION(pvargSrc,punkVal);
1961 if (V_UNION(pvargDest,pdispVal)!=NULL)
1962 ICOM_CALL(AddRef,V_UNION(pvargDest,punkVal));
1963 break;
1964 case( VT_SAFEARRAY ):
1965 SafeArrayCopy(V_UNION(pvargSrc,parray), &V_UNION(pvargDest,parray));
1966 break;
1967 default:
1968 pvargDest->n1.n2.n3 = pvargSrc->n1.n2.n3;
1969 break;
1973 V_VT(pvargDest) = V_VT(pvargSrc);
1978 return res;
1982 /******************************************************************************
1983 * VariantCopyInd [OLEAUT32.11]
1985 * Frees up the destination variant and makes a copy of the source. If
1986 * the source is of type VT_BYREF it performs the necessary indirections.
1988 HRESULT WINAPI VariantCopyInd(VARIANT* pvargDest, VARIANTARG* pvargSrc)
1990 HRESULT res = S_OK;
1992 TRACE("(%p, %p)\n", pvargDest, pvargSrc);
1994 res = ValidateVariantType( V_VT(pvargSrc) );
1996 if( res != S_OK )
1997 return res;
1999 if( V_VT(pvargSrc) & VT_BYREF )
2001 VARIANTARG varg;
2002 VariantInit( &varg );
2004 /* handle the in place copy.
2006 if( pvargDest == pvargSrc )
2008 /* we will use a copy of the source instead.
2010 res = VariantCopy( &varg, pvargSrc );
2011 pvargSrc = &varg;
2014 if( res == S_OK )
2016 res = VariantClear( pvargDest );
2018 if( res == S_OK )
2021 * The VT_ARRAY flag is another way to designate a safearray variant.
2023 if ( V_VT(pvargSrc) & VT_ARRAY)
2025 SafeArrayCopy(*V_UNION(pvargSrc,pparray), &V_UNION(pvargDest,parray));
2027 else
2029 /* In the case of by reference we need
2030 * to copy the date pointed to by the variant.
2033 /* Get the variant type.
2035 switch( V_VT(pvargSrc) & VT_TYPEMASK )
2037 case( VT_BSTR ):
2038 V_UNION(pvargDest,bstrVal) = SYSDUPSTRING( *(V_UNION(pvargSrc,pbstrVal)) );
2039 break;
2040 case( VT_DISPATCH ):
2041 break;
2042 case( VT_VARIANT ):
2044 /* Prevent from cycling. According to tests on
2045 * VariantCopyInd in Windows and the documentation
2046 * this API dereferences the inner Variants to only one depth.
2047 * If the inner Variant itself contains an
2048 * other inner variant the E_INVALIDARG error is
2049 * returned.
2051 if( pvargSrc->n1.n2.wReserved1 & PROCESSING_INNER_VARIANT )
2053 /* If we get here we are attempting to deference
2054 * an inner variant that that is itself contained
2055 * in an inner variant so report E_INVALIDARG error.
2057 res = E_INVALIDARG;
2059 else
2061 /* Set the processing inner variant flag.
2062 * We will set this flag in the inner variant
2063 * that will be passed to the VariantCopyInd function.
2065 (V_UNION(pvargSrc,pvarVal))->n1.n2.wReserved1 |= PROCESSING_INNER_VARIANT;
2067 /* Dereference the inner variant.
2069 res = VariantCopyInd( pvargDest, V_UNION(pvargSrc,pvarVal) );
2070 /* We must also copy its type, I think.
2072 V_VT(pvargSrc) = V_VT(V_UNION(pvargSrc,pvarVal));
2075 break;
2076 case( VT_UNKNOWN ):
2077 break;
2078 case( VT_SAFEARRAY ):
2079 SafeArrayCopy(*V_UNION(pvargSrc,pparray), &V_UNION(pvargDest,parray));
2080 break;
2081 default:
2082 /* This is a by reference Variant which means that the union
2083 * part of the Variant contains a pointer to some data of
2084 * type "V_VT(pvargSrc) & VT_TYPEMASK".
2085 * We will deference this data in a generic fashion using
2086 * the void pointer "Variant.u.byref".
2087 * We will copy this data into the union of the destination
2088 * Variant.
2090 memcpy( &pvargDest->n1.n2.n3, V_UNION(pvargSrc,byref), SizeOfVariantData( pvargSrc ) );
2091 break;
2095 if (res == S_OK) V_VT(pvargDest) = V_VT(pvargSrc) & VT_TYPEMASK;
2099 /* this should not fail.
2101 VariantClear( &varg );
2103 else
2105 res = VariantCopy( pvargDest, pvargSrc );
2108 return res;
2111 /******************************************************************************
2112 * VariantChangeType [OLEAUT32.12]
2114 HRESULT WINAPI VariantChangeType(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
2115 USHORT wFlags, VARTYPE vt)
2117 return VariantChangeTypeEx( pvargDest, pvargSrc, 0, wFlags, vt );
2120 /******************************************************************************
2121 * VariantChangeTypeEx [OLEAUT32.147]
2123 HRESULT WINAPI VariantChangeTypeEx(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
2124 LCID lcid, USHORT wFlags, VARTYPE vt)
2126 HRESULT res = S_OK;
2127 VARIANTARG varg;
2128 VariantInit( &varg );
2130 TRACE("(%p, %p, %ld, %u, %u) vt=%d\n", pvargDest, pvargSrc, lcid, wFlags, vt, V_VT(pvargSrc));
2131 TRACE("Src Var:\n");
2132 dump_Variant(pvargSrc);
2134 /* validate our source argument.
2136 res = ValidateVariantType( V_VT(pvargSrc) );
2138 /* validate the vartype.
2140 if( res == S_OK )
2142 res = ValidateVt( vt );
2145 /* if we are doing an in-place conversion make a copy of the source.
2147 if( res == S_OK && pvargDest == pvargSrc )
2149 res = VariantCopy( &varg, pvargSrc );
2150 pvargSrc = &varg;
2153 if( res == S_OK )
2155 /* free up the destination variant.
2157 res = VariantClear( pvargDest );
2160 if( res == S_OK )
2162 if( V_VT(pvargSrc) & VT_BYREF )
2164 /* Convert the source variant to a "byvalue" variant.
2166 VARIANTARG Variant;
2167 VariantInit( &Variant );
2168 res = VariantCopyInd( &Variant, pvargSrc );
2169 if( res == S_OK )
2171 res = Coerce( pvargDest, lcid, wFlags, &Variant, vt );
2172 /* this should not fail.
2174 VariantClear( &Variant );
2178 else
2180 /* Use the current "byvalue" source variant.
2182 res = Coerce( pvargDest, lcid, wFlags, pvargSrc, vt );
2185 /* this should not fail.
2187 VariantClear( &varg );
2189 /* set the type of the destination
2191 if ( res == S_OK )
2192 V_VT(pvargDest) = vt;
2194 TRACE("Dest Var:\n");
2195 dump_Variant(pvargDest);
2197 return res;
2203 /******************************************************************************
2204 * VarUI1FromI2 [OLEAUT32.130]
2206 HRESULT WINAPI VarUI1FromI2(short sIn, BYTE* pbOut)
2208 TRACE("( %d, %p ), stub\n", sIn, pbOut );
2210 /* Check range of value.
2212 if( sIn < UI1_MIN || sIn > UI1_MAX )
2214 return DISP_E_OVERFLOW;
2217 *pbOut = (BYTE) sIn;
2219 return S_OK;
2222 /******************************************************************************
2223 * VarUI1FromI4 [OLEAUT32.131]
2225 HRESULT WINAPI VarUI1FromI4(LONG lIn, BYTE* pbOut)
2227 TRACE("( %ld, %p ), stub\n", lIn, pbOut );
2229 /* Check range of value.
2231 if( lIn < UI1_MIN || lIn > UI1_MAX )
2233 return DISP_E_OVERFLOW;
2236 *pbOut = (BYTE) lIn;
2238 return S_OK;
2242 /******************************************************************************
2243 * VarUI1FromR4 [OLEAUT32.132]
2245 HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut)
2247 TRACE("( %f, %p ), stub\n", fltIn, pbOut );
2249 /* Check range of value.
2251 fltIn = round( fltIn );
2252 if( fltIn < UI1_MIN || fltIn > UI1_MAX )
2254 return DISP_E_OVERFLOW;
2257 *pbOut = (BYTE) fltIn;
2259 return S_OK;
2262 /******************************************************************************
2263 * VarUI1FromR8 [OLEAUT32.133]
2265 HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut)
2267 TRACE("( %f, %p ), stub\n", dblIn, pbOut );
2269 /* Check range of value.
2271 dblIn = round( dblIn );
2272 if( dblIn < UI1_MIN || dblIn > UI1_MAX )
2274 return DISP_E_OVERFLOW;
2277 *pbOut = (BYTE) dblIn;
2279 return S_OK;
2282 /******************************************************************************
2283 * VarUI1FromDate [OLEAUT32.135]
2285 HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut)
2287 TRACE("( %f, %p ), stub\n", dateIn, pbOut );
2289 /* Check range of value.
2291 dateIn = round( dateIn );
2292 if( dateIn < UI1_MIN || dateIn > UI1_MAX )
2294 return DISP_E_OVERFLOW;
2297 *pbOut = (BYTE) dateIn;
2299 return S_OK;
2302 /******************************************************************************
2303 * VarUI1FromBool [OLEAUT32.138]
2305 HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut)
2307 TRACE("( %d, %p ), stub\n", boolIn, pbOut );
2309 *pbOut = (BYTE) boolIn;
2311 return S_OK;
2314 /******************************************************************************
2315 * VarUI1FromI1 [OLEAUT32.237]
2317 HRESULT WINAPI VarUI1FromI1(CHAR cIn, BYTE* pbOut)
2319 TRACE("( %c, %p ), stub\n", cIn, pbOut );
2321 *pbOut = cIn;
2323 return S_OK;
2326 /******************************************************************************
2327 * VarUI1FromUI2 [OLEAUT32.238]
2329 HRESULT WINAPI VarUI1FromUI2(USHORT uiIn, BYTE* pbOut)
2331 TRACE("( %d, %p ), stub\n", uiIn, pbOut );
2333 /* Check range of value.
2335 if( uiIn > UI1_MAX )
2337 return DISP_E_OVERFLOW;
2340 *pbOut = (BYTE) uiIn;
2342 return S_OK;
2345 /******************************************************************************
2346 * VarUI1FromUI4 [OLEAUT32.239]
2348 HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut)
2350 TRACE("( %ld, %p ), stub\n", ulIn, pbOut );
2352 /* Check range of value.
2354 if( ulIn > UI1_MAX )
2356 return DISP_E_OVERFLOW;
2359 *pbOut = (BYTE) ulIn;
2361 return S_OK;
2365 /******************************************************************************
2366 * VarUI1FromStr [OLEAUT32.136]
2368 HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut)
2370 double dValue = 0.0;
2371 LPSTR pNewString = NULL;
2373 TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, pbOut );
2375 /* Check if we have a valid argument
2377 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2378 RemoveCharacterFromString( pNewString, "," );
2379 if( IsValidRealString( pNewString ) == FALSE )
2381 return DISP_E_TYPEMISMATCH;
2384 /* Convert the valid string to a floating point number.
2386 dValue = atof( pNewString );
2388 /* We don't need the string anymore so free it.
2390 HeapFree( GetProcessHeap(), 0 , pNewString );
2392 /* Check range of value.
2394 dValue = round( dValue );
2395 if( dValue < UI1_MIN || dValue > UI1_MAX )
2397 return DISP_E_OVERFLOW;
2400 *pbOut = (BYTE) dValue;
2402 return S_OK;
2405 /**********************************************************************
2406 * VarUI1FromCy [OLEAUT32.134]
2407 * Convert currency to unsigned char
2409 HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut) {
2410 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2412 if (t > UI1_MAX || t < UI1_MIN) return DISP_E_OVERFLOW;
2414 *pbOut = (BYTE)t;
2415 return S_OK;
2418 /******************************************************************************
2419 * VarI2FromUI1 [OLEAUT32.48]
2421 HRESULT WINAPI VarI2FromUI1(BYTE bIn, short* psOut)
2423 TRACE("( 0x%08x, %p ), stub\n", bIn, psOut );
2425 *psOut = (short) bIn;
2427 return S_OK;
2430 /******************************************************************************
2431 * VarI2FromI4 [OLEAUT32.49]
2433 HRESULT WINAPI VarI2FromI4(LONG lIn, short* psOut)
2435 TRACE("( %lx, %p ), stub\n", lIn, psOut );
2437 /* Check range of value.
2439 if( lIn < I2_MIN || lIn > I2_MAX )
2441 return DISP_E_OVERFLOW;
2444 *psOut = (short) lIn;
2446 return S_OK;
2449 /******************************************************************************
2450 * VarI2FromR4 [OLEAUT32.50]
2452 HRESULT WINAPI VarI2FromR4(FLOAT fltIn, short* psOut)
2454 TRACE("( %f, %p ), stub\n", fltIn, psOut );
2456 /* Check range of value.
2458 fltIn = round( fltIn );
2459 if( fltIn < I2_MIN || fltIn > I2_MAX )
2461 return DISP_E_OVERFLOW;
2464 *psOut = (short) fltIn;
2466 return S_OK;
2469 /******************************************************************************
2470 * VarI2FromR8 [OLEAUT32.51]
2472 HRESULT WINAPI VarI2FromR8(double dblIn, short* psOut)
2474 TRACE("( %f, %p ), stub\n", dblIn, psOut );
2476 /* Check range of value.
2478 dblIn = round( dblIn );
2479 if( dblIn < I2_MIN || dblIn > I2_MAX )
2481 return DISP_E_OVERFLOW;
2484 *psOut = (short) dblIn;
2486 return S_OK;
2489 /******************************************************************************
2490 * VarI2FromDate [OLEAUT32.53]
2492 HRESULT WINAPI VarI2FromDate(DATE dateIn, short* psOut)
2494 TRACE("( %f, %p ), stub\n", dateIn, psOut );
2496 /* Check range of value.
2498 dateIn = round( dateIn );
2499 if( dateIn < I2_MIN || dateIn > I2_MAX )
2501 return DISP_E_OVERFLOW;
2504 *psOut = (short) dateIn;
2506 return S_OK;
2509 /******************************************************************************
2510 * VarI2FromBool [OLEAUT32.56]
2512 HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, short* psOut)
2514 TRACE("( %d, %p ), stub\n", boolIn, psOut );
2516 *psOut = (short) boolIn;
2518 return S_OK;
2521 /******************************************************************************
2522 * VarI2FromI1 [OLEAUT32.205]
2524 HRESULT WINAPI VarI2FromI1(CHAR cIn, short* psOut)
2526 TRACE("( %c, %p ), stub\n", cIn, psOut );
2528 *psOut = (short) cIn;
2530 return S_OK;
2533 /******************************************************************************
2534 * VarI2FromUI2 [OLEAUT32.206]
2536 HRESULT WINAPI VarI2FromUI2(USHORT uiIn, short* psOut)
2538 TRACE("( %d, %p ), stub\n", uiIn, psOut );
2540 /* Check range of value.
2542 if( uiIn > I2_MAX )
2544 return DISP_E_OVERFLOW;
2547 *psOut = (short) uiIn;
2549 return S_OK;
2552 /******************************************************************************
2553 * VarI2FromUI4 [OLEAUT32.207]
2555 HRESULT WINAPI VarI2FromUI4(ULONG ulIn, short* psOut)
2557 TRACE("( %lx, %p ), stub\n", ulIn, psOut );
2559 /* Check range of value.
2561 if( ulIn < I2_MIN || ulIn > I2_MAX )
2563 return DISP_E_OVERFLOW;
2566 *psOut = (short) ulIn;
2568 return S_OK;
2571 /******************************************************************************
2572 * VarI2FromStr [OLEAUT32.54]
2574 HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, short* psOut)
2576 double dValue = 0.0;
2577 LPSTR pNewString = NULL;
2579 TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, psOut );
2581 /* Check if we have a valid argument
2583 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2584 RemoveCharacterFromString( pNewString, "," );
2585 if( IsValidRealString( pNewString ) == FALSE )
2587 return DISP_E_TYPEMISMATCH;
2590 /* Convert the valid string to a floating point number.
2592 dValue = atof( pNewString );
2594 /* We don't need the string anymore so free it.
2596 HeapFree( GetProcessHeap(), 0, pNewString );
2598 /* Check range of value.
2600 dValue = round( dValue );
2601 if( dValue < I2_MIN || dValue > I2_MAX )
2603 return DISP_E_OVERFLOW;
2606 *psOut = (short) dValue;
2608 return S_OK;
2611 /**********************************************************************
2612 * VarI2FromCy [OLEAUT32.52]
2613 * Convert currency to signed short
2615 HRESULT WINAPI VarI2FromCy(CY cyIn, short* psOut) {
2616 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2618 if (t > I2_MAX || t < I2_MIN) return DISP_E_OVERFLOW;
2620 *psOut = (SHORT)t;
2621 return S_OK;
2624 /******************************************************************************
2625 * VarI4FromUI1 [OLEAUT32.58]
2627 HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG* plOut)
2629 TRACE("( %X, %p ), stub\n", bIn, plOut );
2631 *plOut = (LONG) bIn;
2633 return S_OK;
2637 /******************************************************************************
2638 * VarI4FromR4 [OLEAUT32.60]
2640 HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG* plOut)
2642 TRACE("( %f, %p ), stub\n", fltIn, plOut );
2644 /* Check range of value.
2646 fltIn = round( fltIn );
2647 if( fltIn < I4_MIN || fltIn > I4_MAX )
2649 return DISP_E_OVERFLOW;
2652 *plOut = (LONG) fltIn;
2654 return S_OK;
2657 /******************************************************************************
2658 * VarI4FromR8 [OLEAUT32.61]
2660 HRESULT WINAPI VarI4FromR8(double dblIn, LONG* plOut)
2662 TRACE("( %f, %p ), stub\n", dblIn, plOut );
2664 /* Check range of value.
2666 dblIn = round( dblIn );
2667 if( dblIn < I4_MIN || dblIn > I4_MAX )
2669 return DISP_E_OVERFLOW;
2672 *plOut = (LONG) dblIn;
2674 return S_OK;
2677 /******************************************************************************
2678 * VarI4FromDate [OLEAUT32.63]
2680 HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG* plOut)
2682 TRACE("( %f, %p ), stub\n", dateIn, plOut );
2684 /* Check range of value.
2686 dateIn = round( dateIn );
2687 if( dateIn < I4_MIN || dateIn > I4_MAX )
2689 return DISP_E_OVERFLOW;
2692 *plOut = (LONG) dateIn;
2694 return S_OK;
2697 /******************************************************************************
2698 * VarI4FromBool [OLEAUT32.66]
2700 HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG* plOut)
2702 TRACE("( %d, %p ), stub\n", boolIn, plOut );
2704 *plOut = (LONG) boolIn;
2706 return S_OK;
2709 /******************************************************************************
2710 * VarI4FromI1 [OLEAUT32.209]
2712 HRESULT WINAPI VarI4FromI1(CHAR cIn, LONG* plOut)
2714 TRACE("( %c, %p ), stub\n", cIn, plOut );
2716 *plOut = (LONG) cIn;
2718 return S_OK;
2721 /******************************************************************************
2722 * VarI4FromUI2 [OLEAUT32.210]
2724 HRESULT WINAPI VarI4FromUI2(USHORT uiIn, LONG* plOut)
2726 TRACE("( %d, %p ), stub\n", uiIn, plOut );
2728 *plOut = (LONG) uiIn;
2730 return S_OK;
2733 /******************************************************************************
2734 * VarI4FromUI4 [OLEAUT32.211]
2736 HRESULT WINAPI VarI4FromUI4(ULONG ulIn, LONG* plOut)
2738 TRACE("( %lx, %p ), stub\n", ulIn, plOut );
2740 /* Check range of value.
2742 if( ulIn < I4_MIN || ulIn > I4_MAX )
2744 return DISP_E_OVERFLOW;
2747 *plOut = (LONG) ulIn;
2749 return S_OK;
2752 /******************************************************************************
2753 * VarI4FromI2 [OLEAUT32.59]
2755 HRESULT WINAPI VarI4FromI2(short sIn, LONG* plOut)
2757 TRACE("( %d, %p ), stub\n", sIn, plOut );
2759 *plOut = (LONG) sIn;
2761 return S_OK;
2764 /******************************************************************************
2765 * VarI4FromStr [OLEAUT32.64]
2767 HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG* plOut)
2769 double dValue = 0.0;
2770 LPSTR pNewString = NULL;
2772 TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, plOut );
2774 /* Check if we have a valid argument
2776 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2777 RemoveCharacterFromString( pNewString, "," );
2778 if( IsValidRealString( pNewString ) == FALSE )
2780 return DISP_E_TYPEMISMATCH;
2783 /* Convert the valid string to a floating point number.
2785 dValue = atof( pNewString );
2787 /* We don't need the string anymore so free it.
2789 HeapFree( GetProcessHeap(), 0, pNewString );
2791 /* Check range of value.
2793 dValue = round( dValue );
2794 if( dValue < I4_MIN || dValue > I4_MAX )
2796 return DISP_E_OVERFLOW;
2799 *plOut = (LONG) dValue;
2801 return S_OK;
2804 /**********************************************************************
2805 * VarI4FromCy [OLEAUT32.62]
2806 * Convert currency to signed long
2808 HRESULT WINAPI VarI4FromCy(CY cyIn, LONG* plOut) {
2809 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2811 if (t > I4_MAX || t < I4_MIN) return DISP_E_OVERFLOW;
2813 *plOut = (LONG)t;
2814 return S_OK;
2817 /******************************************************************************
2818 * VarR4FromUI1 [OLEAUT32.68]
2820 HRESULT WINAPI VarR4FromUI1(BYTE bIn, FLOAT* pfltOut)
2822 TRACE("( %X, %p ), stub\n", bIn, pfltOut );
2824 *pfltOut = (FLOAT) bIn;
2826 return S_OK;
2829 /******************************************************************************
2830 * VarR4FromI2 [OLEAUT32.69]
2832 HRESULT WINAPI VarR4FromI2(short sIn, FLOAT* pfltOut)
2834 TRACE("( %d, %p ), stub\n", sIn, pfltOut );
2836 *pfltOut = (FLOAT) sIn;
2838 return S_OK;
2841 /******************************************************************************
2842 * VarR4FromI4 [OLEAUT32.70]
2844 HRESULT WINAPI VarR4FromI4(LONG lIn, FLOAT* pfltOut)
2846 TRACE("( %lx, %p ), stub\n", lIn, pfltOut );
2848 *pfltOut = (FLOAT) lIn;
2850 return S_OK;
2853 /******************************************************************************
2854 * VarR4FromR8 [OLEAUT32.71]
2856 HRESULT WINAPI VarR4FromR8(double dblIn, FLOAT* pfltOut)
2858 TRACE("( %f, %p ), stub\n", dblIn, pfltOut );
2860 /* Check range of value.
2862 if( dblIn < -(FLT_MAX) || dblIn > FLT_MAX )
2864 return DISP_E_OVERFLOW;
2867 *pfltOut = (FLOAT) dblIn;
2869 return S_OK;
2872 /******************************************************************************
2873 * VarR4FromDate [OLEAUT32.73]
2875 HRESULT WINAPI VarR4FromDate(DATE dateIn, FLOAT* pfltOut)
2877 TRACE("( %f, %p ), stub\n", dateIn, pfltOut );
2879 /* Check range of value.
2881 if( dateIn < -(FLT_MAX) || dateIn > FLT_MAX )
2883 return DISP_E_OVERFLOW;
2886 *pfltOut = (FLOAT) dateIn;
2888 return S_OK;
2891 /******************************************************************************
2892 * VarR4FromBool [OLEAUT32.76]
2894 HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, FLOAT* pfltOut)
2896 TRACE("( %d, %p ), stub\n", boolIn, pfltOut );
2898 *pfltOut = (FLOAT) boolIn;
2900 return S_OK;
2903 /******************************************************************************
2904 * VarR4FromI1 [OLEAUT32.213]
2906 HRESULT WINAPI VarR4FromI1(CHAR cIn, FLOAT* pfltOut)
2908 TRACE("( %c, %p ), stub\n", cIn, pfltOut );
2910 *pfltOut = (FLOAT) cIn;
2912 return S_OK;
2915 /******************************************************************************
2916 * VarR4FromUI2 [OLEAUT32.214]
2918 HRESULT WINAPI VarR4FromUI2(USHORT uiIn, FLOAT* pfltOut)
2920 TRACE("( %d, %p ), stub\n", uiIn, pfltOut );
2922 *pfltOut = (FLOAT) uiIn;
2924 return S_OK;
2927 /******************************************************************************
2928 * VarR4FromUI4 [OLEAUT32.215]
2930 HRESULT WINAPI VarR4FromUI4(ULONG ulIn, FLOAT* pfltOut)
2932 TRACE("( %ld, %p ), stub\n", ulIn, pfltOut );
2934 *pfltOut = (FLOAT) ulIn;
2936 return S_OK;
2939 /******************************************************************************
2940 * VarR4FromStr [OLEAUT32.74]
2942 HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, FLOAT* pfltOut)
2944 double dValue = 0.0;
2945 LPSTR pNewString = NULL;
2947 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pfltOut );
2949 /* Check if we have a valid argument
2951 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2952 RemoveCharacterFromString( pNewString, "," );
2953 if( IsValidRealString( pNewString ) == FALSE )
2955 return DISP_E_TYPEMISMATCH;
2958 /* Convert the valid string to a floating point number.
2960 dValue = atof( pNewString );
2962 /* We don't need the string anymore so free it.
2964 HeapFree( GetProcessHeap(), 0, pNewString );
2966 /* Check range of value.
2968 if( dValue < -(FLT_MAX) || dValue > FLT_MAX )
2970 return DISP_E_OVERFLOW;
2973 *pfltOut = (FLOAT) dValue;
2975 return S_OK;
2978 /**********************************************************************
2979 * VarR4FromCy [OLEAUT32.72]
2980 * Convert currency to float
2982 HRESULT WINAPI VarR4FromCy(CY cyIn, FLOAT* pfltOut) {
2983 *pfltOut = (FLOAT)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2985 return S_OK;
2988 /******************************************************************************
2989 * VarR8FromUI1 [OLEAUT32.78]
2991 HRESULT WINAPI VarR8FromUI1(BYTE bIn, double* pdblOut)
2993 TRACE("( %d, %p ), stub\n", bIn, pdblOut );
2995 *pdblOut = (double) bIn;
2997 return S_OK;
3000 /******************************************************************************
3001 * VarR8FromI2 [OLEAUT32.79]
3003 HRESULT WINAPI VarR8FromI2(short sIn, double* pdblOut)
3005 TRACE("( %d, %p ), stub\n", sIn, pdblOut );
3007 *pdblOut = (double) sIn;
3009 return S_OK;
3012 /******************************************************************************
3013 * VarR8FromI4 [OLEAUT32.80]
3015 HRESULT WINAPI VarR8FromI4(LONG lIn, double* pdblOut)
3017 TRACE("( %ld, %p ), stub\n", lIn, pdblOut );
3019 *pdblOut = (double) lIn;
3021 return S_OK;
3024 /******************************************************************************
3025 * VarR8FromR4 [OLEAUT32.81]
3027 HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double* pdblOut)
3029 TRACE("( %f, %p ), stub\n", fltIn, pdblOut );
3031 *pdblOut = (double) fltIn;
3033 return S_OK;
3036 /******************************************************************************
3037 * VarR8FromDate [OLEAUT32.83]
3039 HRESULT WINAPI VarR8FromDate(DATE dateIn, double* pdblOut)
3041 TRACE("( %f, %p ), stub\n", dateIn, pdblOut );
3043 *pdblOut = (double) dateIn;
3045 return S_OK;
3048 /******************************************************************************
3049 * VarR8FromBool [OLEAUT32.86]
3051 HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double* pdblOut)
3053 TRACE("( %d, %p ), stub\n", boolIn, pdblOut );
3055 *pdblOut = (double) boolIn;
3057 return S_OK;
3060 /******************************************************************************
3061 * VarR8FromI1 [OLEAUT32.217]
3063 HRESULT WINAPI VarR8FromI1(CHAR cIn, double* pdblOut)
3065 TRACE("( %c, %p ), stub\n", cIn, pdblOut );
3067 *pdblOut = (double) cIn;
3069 return S_OK;
3072 /******************************************************************************
3073 * VarR8FromUI2 [OLEAUT32.218]
3075 HRESULT WINAPI VarR8FromUI2(USHORT uiIn, double* pdblOut)
3077 TRACE("( %d, %p ), stub\n", uiIn, pdblOut );
3079 *pdblOut = (double) uiIn;
3081 return S_OK;
3084 /******************************************************************************
3085 * VarR8FromUI4 [OLEAUT32.219]
3087 HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double* pdblOut)
3089 TRACE("( %ld, %p ), stub\n", ulIn, pdblOut );
3091 *pdblOut = (double) ulIn;
3093 return S_OK;
3096 /******************************************************************************
3097 * VarR8FromStr [OLEAUT32.84]
3099 HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double* pdblOut)
3101 double dValue = 0.0;
3102 LPSTR pNewString = NULL;
3104 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3105 TRACE("( %s, %ld, %ld, %p ), stub\n", pNewString, lcid, dwFlags, pdblOut );
3107 /* Check if we have a valid argument
3109 RemoveCharacterFromString( pNewString, "," );
3110 if( IsValidRealString( pNewString ) == FALSE )
3112 return DISP_E_TYPEMISMATCH;
3115 /* Convert the valid string to a floating point number.
3117 dValue = atof( pNewString );
3119 /* We don't need the string anymore so free it.
3121 HeapFree( GetProcessHeap(), 0, pNewString );
3123 *pdblOut = dValue;
3125 return S_OK;
3128 /**********************************************************************
3129 * VarR8FromCy [OLEAUT32.82]
3130 * Convert currency to double
3132 HRESULT WINAPI VarR8FromCy(CY cyIn, double* pdblOut) {
3133 *pdblOut = (double)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3134 TRACE("%lu %ld -> %f\n", cyIn.s.Hi, cyIn.s.Lo, *pdblOut);
3135 return S_OK;
3138 /******************************************************************************
3139 * VarDateFromUI1 [OLEAUT32.88]
3141 HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
3143 TRACE("( %d, %p ), stub\n", bIn, pdateOut );
3145 *pdateOut = (DATE) bIn;
3147 return S_OK;
3150 /******************************************************************************
3151 * VarDateFromI2 [OLEAUT32.89]
3153 HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
3155 TRACE("( %d, %p ), stub\n", sIn, pdateOut );
3157 *pdateOut = (DATE) sIn;
3159 return S_OK;
3162 /******************************************************************************
3163 * VarDateFromI4 [OLEAUT32.90]
3165 HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
3167 TRACE("( %ld, %p ), stub\n", lIn, pdateOut );
3169 if( lIn < DATE_MIN || lIn > DATE_MAX )
3171 return DISP_E_OVERFLOW;
3174 *pdateOut = (DATE) lIn;
3176 return S_OK;
3179 /******************************************************************************
3180 * VarDateFromR4 [OLEAUT32.91]
3182 HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
3184 TRACE("( %f, %p ), stub\n", fltIn, pdateOut );
3186 if( ceil(fltIn) < DATE_MIN || floor(fltIn) > DATE_MAX )
3188 return DISP_E_OVERFLOW;
3191 *pdateOut = (DATE) fltIn;
3193 return S_OK;
3196 /******************************************************************************
3197 * VarDateFromR8 [OLEAUT32.92]
3199 HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
3201 TRACE("( %f, %p ), stub\n", dblIn, pdateOut );
3203 if( ceil(dblIn) < DATE_MIN || floor(dblIn) > DATE_MAX )
3205 return DISP_E_OVERFLOW;
3208 *pdateOut = (DATE) dblIn;
3210 return S_OK;
3213 /******************************************************************************
3214 * VarDateFromStr [OLEAUT32.94]
3215 * The string representing the date is composed of two parts, a date and time.
3217 * The format of the time is has follows:
3218 * hh[:mm][:ss][AM|PM]
3219 * Whitespace can be inserted anywhere between these tokens. A whitespace consists
3220 * of space and/or tab characters, which are ignored.
3222 * The formats for the date part are has follows:
3223 * mm/[dd/][yy]yy
3224 * [dd/]mm/[yy]yy
3225 * [yy]yy/mm/dd
3226 * January dd[,] [yy]yy
3227 * dd January [yy]yy
3228 * [yy]yy January dd
3229 * Whitespace can be inserted anywhere between these tokens.
3231 * The formats for the date and time string are has follows.
3232 * date[whitespace][time]
3233 * [time][whitespace]date
3235 * These are the only characters allowed in a string representing a date and time:
3236 * [A-Z] [a-z] [0-9] ':' '-' '/' ',' ' ' '\t'
3238 HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
3240 HRESULT ret = S_OK;
3241 struct tm TM;
3243 memset( &TM, 0, sizeof(TM) );
3245 TRACE("( %p, %lx, %lx, %p ), stub\n", strIn, lcid, dwFlags, pdateOut );
3247 if( DateTimeStringToTm( strIn, dwFlags, &TM ) )
3249 if( TmToDATE( &TM, pdateOut ) == FALSE )
3251 ret = E_INVALIDARG;
3254 else
3256 ret = DISP_E_TYPEMISMATCH;
3258 TRACE("Return value %f\n", *pdateOut);
3259 return ret;
3262 /******************************************************************************
3263 * VarDateFromI1 [OLEAUT32.221]
3265 HRESULT WINAPI VarDateFromI1(CHAR cIn, DATE* pdateOut)
3267 TRACE("( %c, %p ), stub\n", cIn, pdateOut );
3269 *pdateOut = (DATE) cIn;
3271 return S_OK;
3274 /******************************************************************************
3275 * VarDateFromUI2 [OLEAUT32.222]
3277 HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
3279 TRACE("( %d, %p ), stub\n", uiIn, pdateOut );
3281 if( uiIn > DATE_MAX )
3283 return DISP_E_OVERFLOW;
3286 *pdateOut = (DATE) uiIn;
3288 return S_OK;
3291 /******************************************************************************
3292 * VarDateFromUI4 [OLEAUT32.223]
3294 HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
3296 TRACE("( %ld, %p ), stub\n", ulIn, pdateOut );
3298 if( ulIn < DATE_MIN || ulIn > DATE_MAX )
3300 return DISP_E_OVERFLOW;
3303 *pdateOut = (DATE) ulIn;
3305 return S_OK;
3308 /******************************************************************************
3309 * VarDateFromBool [OLEAUT32.96]
3311 HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
3313 TRACE("( %d, %p ), stub\n", boolIn, pdateOut );
3315 *pdateOut = (DATE) boolIn;
3317 return S_OK;
3320 /**********************************************************************
3321 * VarDateFromCy [OLEAUT32.93]
3322 * Convert currency to date
3324 HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut) {
3325 *pdateOut = (DATE)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3327 if (*pdateOut > DATE_MAX || *pdateOut < DATE_MIN) return DISP_E_TYPEMISMATCH;
3328 return S_OK;
3331 /******************************************************************************
3332 * VarBstrFromUI1 [OLEAUT32.108]
3334 HRESULT WINAPI VarBstrFromUI1(BYTE bVal, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3336 TRACE("( %d, %ld, %ld, %p ), stub\n", bVal, lcid, dwFlags, pbstrOut );
3337 sprintf( pBuffer, "%d", bVal );
3339 *pbstrOut = StringDupAtoBstr( pBuffer );
3341 return S_OK;
3344 /******************************************************************************
3345 * VarBstrFromI2 [OLEAUT32.109]
3347 HRESULT WINAPI VarBstrFromI2(short iVal, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3349 TRACE("( %d, %ld, %ld, %p ), stub\n", iVal, lcid, dwFlags, pbstrOut );
3350 sprintf( pBuffer, "%d", iVal );
3351 *pbstrOut = StringDupAtoBstr( pBuffer );
3353 return S_OK;
3356 /******************************************************************************
3357 * VarBstrFromI4 [OLEAUT32.110]
3359 HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3361 TRACE("( %ld, %ld, %ld, %p ), stub\n", lIn, lcid, dwFlags, pbstrOut );
3363 sprintf( pBuffer, "%ld", lIn );
3364 *pbstrOut = StringDupAtoBstr( pBuffer );
3366 return S_OK;
3369 /******************************************************************************
3370 * VarBstrFromR4 [OLEAUT32.111]
3372 HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3374 TRACE("( %f, %ld, %ld, %p ), stub\n", fltIn, lcid, dwFlags, pbstrOut );
3376 sprintf( pBuffer, "%.7g", fltIn );
3377 *pbstrOut = StringDupAtoBstr( pBuffer );
3379 return S_OK;
3382 /******************************************************************************
3383 * VarBstrFromR8 [OLEAUT32.112]
3385 HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3387 TRACE("( %f, %ld, %ld, %p ), stub\n", dblIn, lcid, dwFlags, pbstrOut );
3389 sprintf( pBuffer, "%.15g", dblIn );
3390 *pbstrOut = StringDupAtoBstr( pBuffer );
3392 return S_OK;
3395 /******************************************************************************
3396 * VarBstrFromCy [OLEAUT32.113]
3398 HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut) {
3399 HRESULT rc = S_OK;
3400 double curVal = 0.0;
3402 TRACE("([cyIn], %08lx, %08lx, %p), partial stub (no flags handled).\n", lcid, dwFlags, pbstrOut);
3404 /* Firstly get the currency in a double, then put it in a buffer */
3405 rc = VarR8FromCy(cyIn, &curVal);
3406 if (rc == S_OK) {
3407 sprintf(pBuffer, "%g", curVal);
3408 *pbstrOut = StringDupAtoBstr( pBuffer );
3410 return rc;
3414 /******************************************************************************
3415 * VarBstrFromDate [OLEAUT32.114]
3417 * The date is implemented using an 8 byte floating-point number.
3418 * Days are represented by whole numbers increments starting with 0.00 as
3419 * being December 30 1899, midnight.
3420 * The hours are expressed as the fractional part of the number.
3421 * December 30 1899 at midnight = 0.00
3422 * January 1 1900 at midnight = 2.00
3423 * January 4 1900 at 6 AM = 5.25
3424 * January 4 1900 at noon = 5.50
3425 * December 29 1899 at midnight = -1.00
3426 * December 18 1899 at midnight = -12.00
3427 * December 18 1899 at 6AM = -12.25
3428 * December 18 1899 at 6PM = -12.75
3429 * December 19 1899 at midnight = -11.00
3430 * The tm structure is as follows:
3431 * struct tm {
3432 * int tm_sec; seconds after the minute - [0,59]
3433 * int tm_min; minutes after the hour - [0,59]
3434 * int tm_hour; hours since midnight - [0,23]
3435 * int tm_mday; day of the month - [1,31]
3436 * int tm_mon; months since January - [0,11]
3437 * int tm_year; years
3438 * int tm_wday; days since Sunday - [0,6]
3439 * int tm_yday; days since January 1 - [0,365]
3440 * int tm_isdst; daylight savings time flag
3441 * };
3443 HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3445 struct tm TM;
3446 memset( &TM, 0, sizeof(TM) );
3448 TRACE("( %20.20f, %ld, %ld, %p ), stub\n", dateIn, lcid, dwFlags, pbstrOut );
3450 if( DateToTm( dateIn, dwFlags, &TM ) == FALSE )
3452 return E_INVALIDARG;
3455 if( dwFlags & VAR_DATEVALUEONLY )
3456 strftime( pBuffer, BUFFER_MAX, "%x", &TM );
3457 else if( dwFlags & VAR_TIMEVALUEONLY )
3458 strftime( pBuffer, BUFFER_MAX, "%X", &TM );
3459 else
3460 strftime( pBuffer, BUFFER_MAX, "%x %X", &TM );
3462 TRACE("result: %s\n", pBuffer);
3463 *pbstrOut = StringDupAtoBstr( pBuffer );
3464 return S_OK;
3467 /******************************************************************************
3468 * VarBstrFromBool [OLEAUT32.116]
3470 HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3472 TRACE("( %d, %ld, %ld, %p ), stub\n", boolIn, lcid, dwFlags, pbstrOut );
3474 sprintf( pBuffer, (boolIn == VARIANT_FALSE) ? "False" : "True" );
3476 *pbstrOut = StringDupAtoBstr( pBuffer );
3478 return S_OK;
3481 /******************************************************************************
3482 * VarBstrFromI1 [OLEAUT32.229]
3484 HRESULT WINAPI VarBstrFromI1(CHAR cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3486 TRACE("( %c, %ld, %ld, %p ), stub\n", cIn, lcid, dwFlags, pbstrOut );
3487 sprintf( pBuffer, "%d", cIn );
3488 *pbstrOut = StringDupAtoBstr( pBuffer );
3490 return S_OK;
3493 /******************************************************************************
3494 * VarBstrFromUI2 [OLEAUT32.230]
3496 HRESULT WINAPI VarBstrFromUI2(USHORT uiIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3498 TRACE("( %d, %ld, %ld, %p ), stub\n", uiIn, lcid, dwFlags, pbstrOut );
3499 sprintf( pBuffer, "%d", uiIn );
3500 *pbstrOut = StringDupAtoBstr( pBuffer );
3502 return S_OK;
3505 /******************************************************************************
3506 * VarBstrFromUI4 [OLEAUT32.231]
3508 HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3510 TRACE("( %ld, %ld, %ld, %p ), stub\n", ulIn, lcid, dwFlags, pbstrOut );
3511 sprintf( pBuffer, "%ld", ulIn );
3512 *pbstrOut = StringDupAtoBstr( pBuffer );
3514 return S_OK;
3517 /******************************************************************************
3518 * VarBoolFromUI1 [OLEAUT32.118]
3520 HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL* pboolOut)
3522 TRACE("( %d, %p ), stub\n", bIn, pboolOut );
3524 if( bIn == 0 )
3526 *pboolOut = VARIANT_FALSE;
3528 else
3530 *pboolOut = VARIANT_TRUE;
3533 return S_OK;
3536 /******************************************************************************
3537 * VarBoolFromI2 [OLEAUT32.119]
3539 HRESULT WINAPI VarBoolFromI2(short sIn, VARIANT_BOOL* pboolOut)
3541 TRACE("( %d, %p ), stub\n", sIn, pboolOut );
3543 *pboolOut = (sIn) ? VARIANT_TRUE : VARIANT_FALSE;
3545 return S_OK;
3548 /******************************************************************************
3549 * VarBoolFromI4 [OLEAUT32.120]
3551 HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL* pboolOut)
3553 TRACE("( %ld, %p ), stub\n", lIn, pboolOut );
3555 *pboolOut = (lIn) ? VARIANT_TRUE : VARIANT_FALSE;
3557 return S_OK;
3560 /******************************************************************************
3561 * VarBoolFromR4 [OLEAUT32.121]
3563 HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL* pboolOut)
3565 TRACE("( %f, %p ), stub\n", fltIn, pboolOut );
3567 *pboolOut = (fltIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3569 return S_OK;
3572 /******************************************************************************
3573 * VarBoolFromR8 [OLEAUT32.122]
3575 HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL* pboolOut)
3577 TRACE("( %f, %p ), stub\n", dblIn, pboolOut );
3579 *pboolOut = (dblIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3581 return S_OK;
3584 /******************************************************************************
3585 * VarBoolFromDate [OLEAUT32.123]
3587 HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL* pboolOut)
3589 TRACE("( %f, %p ), stub\n", dateIn, pboolOut );
3591 *pboolOut = (dateIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3593 return S_OK;
3596 /******************************************************************************
3597 * VarBoolFromStr [OLEAUT32.125]
3599 HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL* pboolOut)
3601 HRESULT ret = S_OK;
3602 char* pNewString = NULL;
3604 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pboolOut );
3606 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3608 if( pNewString == NULL || strlen( pNewString ) == 0 )
3610 ret = DISP_E_TYPEMISMATCH;
3613 if( ret == S_OK )
3615 if( strncasecmp( pNewString, "True", strlen( pNewString ) ) == 0 )
3617 *pboolOut = VARIANT_TRUE;
3619 else if( strncasecmp( pNewString, "False", strlen( pNewString ) ) == 0 )
3621 *pboolOut = VARIANT_FALSE;
3623 else
3625 /* Try converting the string to a floating point number.
3627 double dValue = 0.0;
3628 HRESULT res = VarR8FromStr( strIn, lcid, dwFlags, &dValue );
3629 if( res != S_OK )
3631 ret = DISP_E_TYPEMISMATCH;
3633 else
3634 *pboolOut = (dValue == 0.0) ?
3635 VARIANT_FALSE : VARIANT_TRUE;
3639 HeapFree( GetProcessHeap(), 0, pNewString );
3641 return ret;
3644 /******************************************************************************
3645 * VarBoolFromI1 [OLEAUT32.233]
3647 HRESULT WINAPI VarBoolFromI1(CHAR cIn, VARIANT_BOOL* pboolOut)
3649 TRACE("( %c, %p ), stub\n", cIn, pboolOut );
3651 *pboolOut = (cIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3653 return S_OK;
3656 /******************************************************************************
3657 * VarBoolFromUI2 [OLEAUT32.234]
3659 HRESULT WINAPI VarBoolFromUI2(USHORT uiIn, VARIANT_BOOL* pboolOut)
3661 TRACE("( %d, %p ), stub\n", uiIn, pboolOut );
3663 *pboolOut = (uiIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3665 return S_OK;
3668 /******************************************************************************
3669 * VarBoolFromUI4 [OLEAUT32.235]
3671 HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL* pboolOut)
3673 TRACE("( %ld, %p ), stub\n", ulIn, pboolOut );
3675 *pboolOut = (ulIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3677 return S_OK;
3680 /**********************************************************************
3681 * VarBoolFromCy [OLEAUT32.124]
3682 * Convert currency to boolean
3684 HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL* pboolOut) {
3685 if (cyIn.s.Hi || cyIn.s.Lo) *pboolOut = -1;
3686 else *pboolOut = 0;
3688 return S_OK;
3691 /******************************************************************************
3692 * VarI1FromUI1 [OLEAUT32.244]
3694 HRESULT WINAPI VarI1FromUI1(BYTE bIn, CHAR* pcOut)
3696 TRACE("( %d, %p ), stub\n", bIn, pcOut );
3698 /* Check range of value.
3700 if( bIn > CHAR_MAX )
3702 return DISP_E_OVERFLOW;
3705 *pcOut = (CHAR) bIn;
3707 return S_OK;
3710 /******************************************************************************
3711 * VarI1FromI2 [OLEAUT32.245]
3713 HRESULT WINAPI VarI1FromI2(short uiIn, CHAR* pcOut)
3715 TRACE("( %d, %p ), stub\n", uiIn, pcOut );
3717 if( uiIn > CHAR_MAX )
3719 return DISP_E_OVERFLOW;
3722 *pcOut = (CHAR) uiIn;
3724 return S_OK;
3727 /******************************************************************************
3728 * VarI1FromI4 [OLEAUT32.246]
3730 HRESULT WINAPI VarI1FromI4(LONG lIn, CHAR* pcOut)
3732 TRACE("( %ld, %p ), stub\n", lIn, pcOut );
3734 if( lIn < CHAR_MIN || lIn > CHAR_MAX )
3736 return DISP_E_OVERFLOW;
3739 *pcOut = (CHAR) lIn;
3741 return S_OK;
3744 /******************************************************************************
3745 * VarI1FromR4 [OLEAUT32.247]
3747 HRESULT WINAPI VarI1FromR4(FLOAT fltIn, CHAR* pcOut)
3749 TRACE("( %f, %p ), stub\n", fltIn, pcOut );
3751 fltIn = round( fltIn );
3752 if( fltIn < CHAR_MIN || fltIn > CHAR_MAX )
3754 return DISP_E_OVERFLOW;
3757 *pcOut = (CHAR) fltIn;
3759 return S_OK;
3762 /******************************************************************************
3763 * VarI1FromR8 [OLEAUT32.248]
3765 HRESULT WINAPI VarI1FromR8(double dblIn, CHAR* pcOut)
3767 TRACE("( %f, %p ), stub\n", dblIn, pcOut );
3769 dblIn = round( dblIn );
3770 if( dblIn < CHAR_MIN || dblIn > CHAR_MAX )
3772 return DISP_E_OVERFLOW;
3775 *pcOut = (CHAR) dblIn;
3777 return S_OK;
3780 /******************************************************************************
3781 * VarI1FromDate [OLEAUT32.249]
3783 HRESULT WINAPI VarI1FromDate(DATE dateIn, CHAR* pcOut)
3785 TRACE("( %f, %p ), stub\n", dateIn, pcOut );
3787 dateIn = round( dateIn );
3788 if( dateIn < CHAR_MIN || dateIn > CHAR_MAX )
3790 return DISP_E_OVERFLOW;
3793 *pcOut = (CHAR) dateIn;
3795 return S_OK;
3798 /******************************************************************************
3799 * VarI1FromStr [OLEAUT32.251]
3801 HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, CHAR* pcOut)
3803 double dValue = 0.0;
3804 LPSTR pNewString = NULL;
3806 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pcOut );
3808 /* Check if we have a valid argument
3810 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3811 RemoveCharacterFromString( pNewString, "," );
3812 if( IsValidRealString( pNewString ) == FALSE )
3814 return DISP_E_TYPEMISMATCH;
3817 /* Convert the valid string to a floating point number.
3819 dValue = atof( pNewString );
3821 /* We don't need the string anymore so free it.
3823 HeapFree( GetProcessHeap(), 0, pNewString );
3825 /* Check range of value.
3827 dValue = round( dValue );
3828 if( dValue < CHAR_MIN || dValue > CHAR_MAX )
3830 return DISP_E_OVERFLOW;
3833 *pcOut = (CHAR) dValue;
3835 return S_OK;
3838 /******************************************************************************
3839 * VarI1FromBool [OLEAUT32.253]
3841 HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, CHAR* pcOut)
3843 TRACE("( %d, %p ), stub\n", boolIn, pcOut );
3845 *pcOut = (CHAR) boolIn;
3847 return S_OK;
3850 /******************************************************************************
3851 * VarI1FromUI2 [OLEAUT32.254]
3853 HRESULT WINAPI VarI1FromUI2(USHORT uiIn, CHAR* pcOut)
3855 TRACE("( %d, %p ), stub\n", uiIn, pcOut );
3857 if( uiIn > CHAR_MAX )
3859 return DISP_E_OVERFLOW;
3862 *pcOut = (CHAR) uiIn;
3864 return S_OK;
3867 /******************************************************************************
3868 * VarI1FromUI4 [OLEAUT32.255]
3870 HRESULT WINAPI VarI1FromUI4(ULONG ulIn, CHAR* pcOut)
3872 TRACE("( %ld, %p ), stub\n", ulIn, pcOut );
3874 if( ulIn > CHAR_MAX )
3876 return DISP_E_OVERFLOW;
3879 *pcOut = (CHAR) ulIn;
3881 return S_OK;
3884 /**********************************************************************
3885 * VarI1FromCy [OLEAUT32.250]
3886 * Convert currency to signed char
3888 HRESULT WINAPI VarI1FromCy(CY cyIn, CHAR* pcOut) {
3889 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3891 if (t > CHAR_MAX || t < CHAR_MIN) return DISP_E_OVERFLOW;
3893 *pcOut = (CHAR)t;
3894 return S_OK;
3897 /******************************************************************************
3898 * VarUI2FromUI1 [OLEAUT32.257]
3900 HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* puiOut)
3902 TRACE("( %d, %p ), stub\n", bIn, puiOut );
3904 *puiOut = (USHORT) bIn;
3906 return S_OK;
3909 /******************************************************************************
3910 * VarUI2FromI2 [OLEAUT32.258]
3912 HRESULT WINAPI VarUI2FromI2(short uiIn, USHORT* puiOut)
3914 TRACE("( %d, %p ), stub\n", uiIn, puiOut );
3916 if( uiIn < UI2_MIN )
3918 return DISP_E_OVERFLOW;
3921 *puiOut = (USHORT) uiIn;
3923 return S_OK;
3926 /******************************************************************************
3927 * VarUI2FromI4 [OLEAUT32.259]
3929 HRESULT WINAPI VarUI2FromI4(LONG lIn, USHORT* puiOut)
3931 TRACE("( %ld, %p ), stub\n", lIn, puiOut );
3933 if( lIn < UI2_MIN || lIn > UI2_MAX )
3935 return DISP_E_OVERFLOW;
3938 *puiOut = (USHORT) lIn;
3940 return S_OK;
3943 /******************************************************************************
3944 * VarUI2FromR4 [OLEAUT32.260]
3946 HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* puiOut)
3948 TRACE("( %f, %p ), stub\n", fltIn, puiOut );
3950 fltIn = round( fltIn );
3951 if( fltIn < UI2_MIN || fltIn > UI2_MAX )
3953 return DISP_E_OVERFLOW;
3956 *puiOut = (USHORT) fltIn;
3958 return S_OK;
3961 /******************************************************************************
3962 * VarUI2FromR8 [OLEAUT32.261]
3964 HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* puiOut)
3966 TRACE("( %f, %p ), stub\n", dblIn, puiOut );
3968 dblIn = round( dblIn );
3969 if( dblIn < UI2_MIN || dblIn > UI2_MAX )
3971 return DISP_E_OVERFLOW;
3974 *puiOut = (USHORT) dblIn;
3976 return S_OK;
3979 /******************************************************************************
3980 * VarUI2FromDate [OLEAUT32.262]
3982 HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* puiOut)
3984 TRACE("( %f, %p ), stub\n", dateIn, puiOut );
3986 dateIn = round( dateIn );
3987 if( dateIn < UI2_MIN || dateIn > UI2_MAX )
3989 return DISP_E_OVERFLOW;
3992 *puiOut = (USHORT) dateIn;
3994 return S_OK;
3997 /******************************************************************************
3998 * VarUI2FromStr [OLEAUT32.264]
4000 HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* puiOut)
4002 double dValue = 0.0;
4003 LPSTR pNewString = NULL;
4005 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, puiOut );
4007 /* Check if we have a valid argument
4009 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
4010 RemoveCharacterFromString( pNewString, "," );
4011 if( IsValidRealString( pNewString ) == FALSE )
4013 return DISP_E_TYPEMISMATCH;
4016 /* Convert the valid string to a floating point number.
4018 dValue = atof( pNewString );
4020 /* We don't need the string anymore so free it.
4022 HeapFree( GetProcessHeap(), 0, pNewString );
4024 /* Check range of value.
4026 dValue = round( dValue );
4027 if( dValue < UI2_MIN || dValue > UI2_MAX )
4029 return DISP_E_OVERFLOW;
4032 *puiOut = (USHORT) dValue;
4034 return S_OK;
4037 /******************************************************************************
4038 * VarUI2FromBool [OLEAUT32.266]
4040 HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* puiOut)
4042 TRACE("( %d, %p ), stub\n", boolIn, puiOut );
4044 *puiOut = (USHORT) boolIn;
4046 return S_OK;
4049 /******************************************************************************
4050 * VarUI2FromI1 [OLEAUT32.267]
4052 HRESULT WINAPI VarUI2FromI1(CHAR cIn, USHORT* puiOut)
4054 TRACE("( %c, %p ), stub\n", cIn, puiOut );
4056 *puiOut = (USHORT) cIn;
4058 return S_OK;
4061 /******************************************************************************
4062 * VarUI2FromUI4 [OLEAUT32.268]
4064 HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* puiOut)
4066 TRACE("( %ld, %p ), stub\n", ulIn, puiOut );
4068 if( ulIn < UI2_MIN || ulIn > UI2_MAX )
4070 return DISP_E_OVERFLOW;
4073 *puiOut = (USHORT) ulIn;
4075 return S_OK;
4078 /******************************************************************************
4079 * VarUI4FromStr [OLEAUT32.277]
4081 HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG* pulOut)
4083 double dValue = 0.0;
4084 LPSTR pNewString = NULL;
4086 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pulOut );
4088 /* Check if we have a valid argument
4090 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
4091 RemoveCharacterFromString( pNewString, "," );
4092 if( IsValidRealString( pNewString ) == FALSE )
4094 return DISP_E_TYPEMISMATCH;
4097 /* Convert the valid string to a floating point number.
4099 dValue = atof( pNewString );
4101 /* We don't need the string anymore so free it.
4103 HeapFree( GetProcessHeap(), 0, pNewString );
4105 /* Check range of value.
4107 dValue = round( dValue );
4108 if( dValue < UI4_MIN || dValue > UI4_MAX )
4110 return DISP_E_OVERFLOW;
4113 *pulOut = (ULONG) dValue;
4115 return S_OK;
4118 /**********************************************************************
4119 * VarUI2FromCy [OLEAUT32.263]
4120 * Convert currency to unsigned short
4122 HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut) {
4123 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
4125 if (t > UI2_MAX || t < UI2_MIN) return DISP_E_OVERFLOW;
4127 *pusOut = (USHORT)t;
4129 return S_OK;
4132 /******************************************************************************
4133 * VarUI4FromUI1 [OLEAUT32.270]
4135 HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG* pulOut)
4137 TRACE("( %d, %p ), stub\n", bIn, pulOut );
4139 *pulOut = (USHORT) bIn;
4141 return S_OK;
4144 /******************************************************************************
4145 * VarUI4FromI2 [OLEAUT32.271]
4147 HRESULT WINAPI VarUI4FromI2(short uiIn, ULONG* pulOut)
4149 TRACE("( %d, %p ), stub\n", uiIn, pulOut );
4151 if( uiIn < UI4_MIN )
4153 return DISP_E_OVERFLOW;
4156 *pulOut = (ULONG) uiIn;
4158 return S_OK;
4161 /******************************************************************************
4162 * VarUI4FromI4 [OLEAUT32.272]
4164 HRESULT WINAPI VarUI4FromI4(LONG lIn, ULONG* pulOut)
4166 TRACE("( %ld, %p ), stub\n", lIn, pulOut );
4168 if( lIn < UI4_MIN )
4170 return DISP_E_OVERFLOW;
4173 *pulOut = (ULONG) lIn;
4175 return S_OK;
4178 /******************************************************************************
4179 * VarUI4FromR4 [OLEAUT32.273]
4181 HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG* pulOut)
4183 fltIn = round( fltIn );
4184 if( fltIn < UI4_MIN || fltIn > UI4_MAX )
4186 return DISP_E_OVERFLOW;
4189 *pulOut = (ULONG) fltIn;
4191 return S_OK;
4194 /******************************************************************************
4195 * VarUI4FromR8 [OLEAUT32.274]
4197 HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG* pulOut)
4199 TRACE("( %f, %p ), stub\n", dblIn, pulOut );
4201 dblIn = round( dblIn );
4202 if( dblIn < UI4_MIN || dblIn > UI4_MAX )
4204 return DISP_E_OVERFLOW;
4207 *pulOut = (ULONG) dblIn;
4209 return S_OK;
4212 /******************************************************************************
4213 * VarUI4FromDate [OLEAUT32.275]
4215 HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG* pulOut)
4217 TRACE("( %f, %p ), stub\n", dateIn, pulOut );
4219 dateIn = round( dateIn );
4220 if( dateIn < UI4_MIN || dateIn > UI4_MAX )
4222 return DISP_E_OVERFLOW;
4225 *pulOut = (ULONG) dateIn;
4227 return S_OK;
4230 /******************************************************************************
4231 * VarUI4FromBool [OLEAUT32.279]
4233 HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG* pulOut)
4235 TRACE("( %d, %p ), stub\n", boolIn, pulOut );
4237 *pulOut = (ULONG) boolIn;
4239 return S_OK;
4242 /******************************************************************************
4243 * VarUI4FromI1 [OLEAUT32.280]
4245 HRESULT WINAPI VarUI4FromI1(CHAR cIn, ULONG* pulOut)
4247 TRACE("( %c, %p ), stub\n", cIn, pulOut );
4249 *pulOut = (ULONG) cIn;
4251 return S_OK;
4254 /******************************************************************************
4255 * VarUI4FromUI2 [OLEAUT32.281]
4257 HRESULT WINAPI VarUI4FromUI2(USHORT uiIn, ULONG* pulOut)
4259 TRACE("( %d, %p ), stub\n", uiIn, pulOut );
4261 *pulOut = (ULONG) uiIn;
4263 return S_OK;
4266 /**********************************************************************
4267 * VarUI4FromCy [OLEAUT32.276]
4268 * Convert currency to unsigned long
4270 HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG* pulOut) {
4271 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
4273 if (t > UI4_MAX || t < UI4_MIN) return DISP_E_OVERFLOW;
4275 *pulOut = (ULONG)t;
4277 return S_OK;
4280 /**********************************************************************
4281 * VarCyFromUI1 [OLEAUT32.98]
4282 * Convert unsigned char to currency
4284 HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pcyOut) {
4285 pcyOut->s.Hi = 0;
4286 pcyOut->s.Lo = ((ULONG)bIn) * 10000;
4288 return S_OK;
4291 /**********************************************************************
4292 * VarCyFromI2 [OLEAUT32.99]
4293 * Convert signed short to currency
4295 HRESULT WINAPI VarCyFromI2(short sIn, CY* pcyOut) {
4296 if (sIn < 0) pcyOut->s.Hi = -1;
4297 else pcyOut->s.Hi = 0;
4298 pcyOut->s.Lo = ((ULONG)sIn) * 10000;
4300 return S_OK;
4303 /**********************************************************************
4304 * VarCyFromI4 [OLEAUT32.100]
4305 * Convert signed long to currency
4307 HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pcyOut) {
4308 double t = (double)lIn * (double)10000;
4309 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4310 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4311 if (lIn < 0) pcyOut->s.Hi--;
4313 return S_OK;
4316 /**********************************************************************
4317 * VarCyFromR4 [OLEAUT32.101]
4318 * Convert float to currency
4320 HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pcyOut) {
4321 double t = round((double)fltIn * (double)10000);
4322 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4323 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4324 if (fltIn < 0) pcyOut->s.Hi--;
4326 return S_OK;
4329 /**********************************************************************
4330 * VarCyFromR8 [OLEAUT32.102]
4331 * Convert double to currency
4333 HRESULT WINAPI VarCyFromR8(double dblIn, CY* pcyOut) {
4334 double t = round(dblIn * (double)10000);
4335 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4336 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4337 if (dblIn < 0) pcyOut->s.Hi--;
4339 return S_OK;
4342 /**********************************************************************
4343 * VarCyFromDate [OLEAUT32.103]
4344 * Convert date to currency
4346 HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pcyOut) {
4347 double t = round((double)dateIn * (double)10000);
4348 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4349 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4350 if (dateIn < 0) pcyOut->s.Hi--;
4352 return S_OK;
4355 /**********************************************************************
4356 * VarCyFromStr [OLEAUT32.104]
4357 * FIXME: Never tested with decimal seperator other than '.'
4359 HRESULT WINAPI VarCyFromStr(OLECHAR *strIn, LCID lcid, ULONG dwFlags, CY *pcyOut) {
4361 LPSTR pNewString = NULL;
4362 char *decSep = NULL;
4363 char *strPtr,*curPtr = NULL;
4364 int size, rc;
4365 double currencyVal = 0.0;
4368 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
4369 TRACE("( '%s', 0x%08lx, 0x%08lx, %p )\n", pNewString, lcid, dwFlags, pcyOut );
4371 /* Get locale information - Decimal Seperator (size includes 0x00) */
4372 size = GetLocaleInfoA(lcid, LOCALE_SDECIMAL, NULL, 0);
4373 decSep = (char *) malloc(size);
4374 rc = GetLocaleInfoA(lcid, LOCALE_SDECIMAL, decSep, size);
4375 TRACE("Decimal Seperator is '%s'\n", decSep);
4377 /* Now copy to temporary buffer, skipping any character except 0-9 and
4378 the decimal seperator */
4379 curPtr = pBuffer; /* Current position in string being built */
4380 strPtr = pNewString; /* Current position in supplied currenct string */
4382 while (*strPtr) {
4383 /* If decimal seperator, skip it and put '.' in string */
4384 if (strncmp(strPtr, decSep, (size-1)) == 0) {
4385 strPtr = strPtr + (size-1);
4386 *curPtr = '.';
4387 curPtr++;
4388 } else if ((*strPtr == '+' || *strPtr == '-') ||
4389 (*strPtr >= '0' && *strPtr <= '9')) {
4390 *curPtr = *strPtr;
4391 strPtr++;
4392 curPtr++;
4393 } else strPtr++;
4395 *curPtr = 0x00;
4397 /* Try to get currency into a double */
4398 currencyVal = atof(pBuffer);
4399 TRACE("Converted string '%s' to %f\n", pBuffer, currencyVal);
4401 /* Free allocated storage */
4402 HeapFree( GetProcessHeap(), 0, pNewString );
4403 free(decSep);
4405 /* Convert double -> currency using internal routine */
4406 return VarCyFromR8(currencyVal, pcyOut);
4410 /**********************************************************************
4411 * VarCyFromBool [OLEAUT32.106]
4412 * Convert boolean to currency
4414 HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pcyOut) {
4415 if (boolIn < 0) pcyOut->s.Hi = -1;
4416 else pcyOut->s.Hi = 0;
4417 pcyOut->s.Lo = (ULONG)boolIn * (ULONG)10000;
4419 return S_OK;
4422 /**********************************************************************
4423 * VarCyFromI1 [OLEAUT32.225]
4424 * Convert signed char to currency
4426 HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pcyOut) {
4427 if (cIn < 0) pcyOut->s.Hi = -1;
4428 else pcyOut->s.Hi = 0;
4429 pcyOut->s.Lo = (ULONG)cIn * (ULONG)10000;
4431 return S_OK;
4434 /**********************************************************************
4435 * VarCyFromUI2 [OLEAUT32.226]
4436 * Convert unsigned short to currency
4438 HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pcyOut) {
4439 pcyOut->s.Hi = 0;
4440 pcyOut->s.Lo = (ULONG)usIn * (ULONG)10000;
4442 return S_OK;
4445 /**********************************************************************
4446 * VarCyFromUI4 [OLEAUT32.227]
4447 * Convert unsigned long to currency
4449 HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pcyOut) {
4450 double t = (double)ulIn * (double)10000;
4451 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4452 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4454 return S_OK;
4458 /**********************************************************************
4459 * DosDateTimeToVariantTime [OLEAUT32.14]
4460 * Convert dos representation of time to the date and time representation
4461 * stored in a variant.
4463 INT WINAPI DosDateTimeToVariantTime(USHORT wDosDate, USHORT wDosTime,
4464 DATE *pvtime)
4466 struct tm t;
4468 TRACE("( 0x%x, 0x%x, %p ), stub\n", wDosDate, wDosTime, pvtime );
4470 t.tm_sec = (wDosTime & 0x001f) * 2;
4471 t.tm_min = (wDosTime & 0x07e0) >> 5;
4472 t.tm_hour = (wDosTime & 0xf800) >> 11;
4474 t.tm_mday = (wDosDate & 0x001f);
4475 t.tm_mon = (wDosDate & 0x01e0) >> 5;
4476 t.tm_year = ((wDosDate & 0xfe00) >> 9) + 1980;
4478 return TmToDATE( &t, pvtime );
4482 /**********************************************************************
4483 * VarParseNumFromStr [OLEAUT32.46]
4485 HRESULT WINAPI VarParseNumFromStr(OLECHAR * strIn, LCID lcid, ULONG dwFlags,
4486 NUMPARSE * pnumprs, BYTE * rgbDig)
4488 int i,lastent=0;
4489 int cDig;
4490 BOOL foundNum=FALSE;
4492 FIXME("(%s,flags=%lx,....), partial stub!\n",debugstr_w(strIn),dwFlags);
4493 FIXME("numparse: cDig=%d, InFlags=%lx\n",pnumprs->cDig,pnumprs->dwInFlags);
4495 /* The other struct components are to be set by us */
4496 memset(rgbDig,0,pnumprs->cDig);
4498 /* FIXME: Just patching some values in */
4499 pnumprs->nPwr10 = 0;
4500 pnumprs->nBaseShift = 0;
4501 pnumprs->cchUsed = lastent;
4502 pnumprs->dwOutFlags = NUMPRS_DECIMAL;
4504 cDig = 0;
4505 for (i=0; strIn[i] ;i++) {
4506 if ((strIn[i]>='0') && (strIn[i]<='9')) {
4507 foundNum = TRUE;
4508 if (pnumprs->cDig > cDig) {
4509 *(rgbDig++)=strIn[i]-'0';
4510 cDig++;
4511 lastent = i;
4513 } else if ((strIn[i]=='-') && (foundNum==FALSE)) {
4514 pnumprs->dwOutFlags |= NUMPRS_NEG;
4517 pnumprs->cDig = cDig;
4518 TRACE("numparse out: cDig=%d, OutFlags=%lx\n",pnumprs->cDig,pnumprs->dwOutFlags);
4519 return S_OK;
4523 /**********************************************************************
4524 * VarNumFromParseNum [OLEAUT32.47]
4526 HRESULT WINAPI VarNumFromParseNum(NUMPARSE * pnumprs, BYTE * rgbDig,
4527 ULONG dwVtBits, VARIANT * pvar)
4529 DWORD xint;
4530 int i;
4531 FIXME("(..,dwVtBits=%lx,....), partial stub!\n",dwVtBits);
4533 xint = 0;
4534 for (i=0;i<pnumprs->cDig;i++)
4535 xint = xint*10 + rgbDig[i];
4537 if (pnumprs->dwOutFlags & NUMPRS_NEG) {
4538 xint = xint * -1;
4541 VariantInit(pvar);
4542 if (dwVtBits & VTBIT_I4) {
4543 V_VT(pvar) = VT_I4;
4544 V_UNION(pvar,intVal) = xint;
4545 return S_OK;
4547 if (dwVtBits & VTBIT_R8) {
4548 V_VT(pvar) = VT_R8;
4549 V_UNION(pvar,dblVal) = xint;
4550 return S_OK;
4552 if (dwVtBits & VTBIT_R4) {
4553 V_VT(pvar) = VT_R4;
4554 V_UNION(pvar,fltVal) = xint;
4555 return S_OK;
4557 if (dwVtBits & VTBIT_I2) {
4558 V_VT(pvar) = VT_I2;
4559 V_UNION(pvar,iVal) = xint;
4560 return S_OK;
4562 /* FIXME: Currency should be from a double */
4563 if (dwVtBits & VTBIT_CY) {
4564 V_VT(pvar) = VT_CY;
4565 TRACE("Calculated currency is xint=%ld\n", xint);
4566 VarCyFromInt( (int) xint, &V_UNION(pvar,cyVal) );
4567 TRACE("Calculated cy is %ld,%lu\n", V_UNION(pvar,cyVal).s.Hi, V_UNION(pvar,cyVal).s.Lo);
4568 return VarCyFromInt( (int) xint, &V_UNION(pvar,cyVal) );
4571 FIXME("vtbitmask is unsupported %lx, int=%d\n",dwVtBits, (int) xint);
4572 return E_FAIL;
4576 /**********************************************************************
4577 * VariantTimeToDosDateTime [OLEAUT32.13]
4578 * Convert variant representation of time to the date and time representation
4579 * stored in dos.
4581 INT WINAPI VariantTimeToDosDateTime(DATE pvtime, USHORT *wDosDate, USHORT *wDosTime)
4583 struct tm t;
4584 *wDosTime = 0;
4585 *wDosDate = 0;
4587 TRACE("( 0x%x, 0x%x, %p ), stub\n", *wDosDate, *wDosTime, &pvtime );
4589 if (DateToTm(pvtime, 0, &t) < 0) return 0;
4591 *wDosTime = *wDosTime | (t.tm_sec / 2);
4592 *wDosTime = *wDosTime | (t.tm_min << 5);
4593 *wDosTime = *wDosTime | (t.tm_hour << 11);
4595 *wDosDate = *wDosDate | t.tm_mday ;
4596 *wDosDate = *wDosDate | t.tm_mon << 5;
4597 *wDosDate = *wDosDate | ((t.tm_year - 1980) << 9) ;
4599 return 1;
4603 /***********************************************************************
4604 * SystemTimeToVariantTime [OLEAUT32.184]
4606 HRESULT WINAPI SystemTimeToVariantTime( LPSYSTEMTIME lpSystemTime, double *pvtime )
4608 struct tm t;
4610 TRACE(" %d/%d/%d %d:%d:%d\n",
4611 lpSystemTime->wMonth, lpSystemTime->wDay,
4612 lpSystemTime->wYear, lpSystemTime->wHour,
4613 lpSystemTime->wMinute, lpSystemTime->wSecond);
4615 if (lpSystemTime->wYear >= 1900)
4617 t.tm_sec = lpSystemTime->wSecond;
4618 t.tm_min = lpSystemTime->wMinute;
4619 t.tm_hour = lpSystemTime->wHour;
4621 t.tm_mday = lpSystemTime->wDay;
4622 t.tm_mon = lpSystemTime->wMonth - 1; /* tm_mon is 0..11, wMonth is 1..12 */
4623 t.tm_year = lpSystemTime->wYear;
4625 return TmToDATE( &t, pvtime );
4627 else
4629 double tmpDate;
4630 long firstDayOfNextYear;
4631 long thisDay;
4632 long leftInYear;
4633 long result;
4635 double decimalPart = 0.0;
4637 t.tm_sec = lpSystemTime->wSecond;
4638 t.tm_min = lpSystemTime->wMinute;
4639 t.tm_hour = lpSystemTime->wHour;
4641 /* Step year forward the same number of years before 1900 */
4642 t.tm_year = 1900 + 1899 - lpSystemTime->wYear;
4643 t.tm_mon = lpSystemTime->wMonth - 1;
4644 t.tm_mday = lpSystemTime->wDay;
4646 /* Calculate date */
4647 TmToDATE( &t, pvtime );
4649 thisDay = (double) floor( *pvtime );
4650 decimalPart = fmod( *pvtime, thisDay );
4652 /* Now, calculate the same time for the first of Jan that year */
4653 t.tm_mon = 0;
4654 t.tm_mday = 1;
4655 t.tm_sec = 0;
4656 t.tm_min = 0;
4657 t.tm_hour = 0;
4658 t.tm_year = t.tm_year+1;
4659 TmToDATE( &t, &tmpDate );
4660 firstDayOfNextYear = (long) floor(tmpDate);
4662 /* Finally since we know the size of the year, subtract the two to get
4663 remaining time in the year */
4664 leftInYear = firstDayOfNextYear - thisDay;
4666 /* Now we want full years up to the year in question, and remainder of year
4667 of the year in question */
4668 if (isleap(lpSystemTime->wYear) ) {
4669 TRACE("Extra day due to leap year\n");
4670 result = 2.0 - ((firstDayOfNextYear - 366) + leftInYear - 2.0);
4671 } else {
4672 result = 2.0 - ((firstDayOfNextYear - 365) + leftInYear - 2.0);
4674 *pvtime = (double) result + decimalPart;
4675 TRACE("<1899 support: returned %f, 1st day %ld, thisday %ld, left %ld\n", *pvtime, firstDayOfNextYear, thisDay, leftInYear);
4677 return 1;
4680 return 0;
4683 /***********************************************************************
4684 * VariantTimeToSystemTime [OLEAUT32.185]
4686 HRESULT WINAPI VariantTimeToSystemTime( double vtime, LPSYSTEMTIME lpSystemTime )
4688 double t = 0, timeofday = 0;
4690 static const BYTE Days_Per_Month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4691 static const BYTE Days_Per_Month_LY[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4693 /* The Month_Code is used to find the Day of the Week (LY = LeapYear)*/
4694 static const BYTE Month_Code[] = {0, 1, 4, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6};
4695 static const BYTE Month_Code_LY[] = {0, 0, 3, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6};
4697 /* The Century_Code is used to find the Day of the Week */
4698 static const BYTE Century_Code[] = {0, 6, 4, 2};
4700 struct tm r;
4702 TRACE(" Variant = %f SYSTEMTIME ptr %p\n", vtime, lpSystemTime);
4704 if (vtime >= 0)
4707 if (DateToTm(vtime, 0, &r ) <= 0) return 0;
4709 lpSystemTime->wSecond = r.tm_sec;
4710 lpSystemTime->wMinute = r.tm_min;
4711 lpSystemTime->wHour = r.tm_hour;
4712 lpSystemTime->wDay = r.tm_mday;
4713 lpSystemTime->wMonth = r.tm_mon;
4715 if (lpSystemTime->wMonth == 12)
4716 lpSystemTime->wMonth = 1;
4717 else
4718 lpSystemTime->wMonth++;
4720 lpSystemTime->wYear = r.tm_year;
4722 else
4724 vtime = -1*vtime;
4726 if (DateToTm(vtime, 0, &r ) <= 0) return 0;
4728 lpSystemTime->wSecond = r.tm_sec;
4729 lpSystemTime->wMinute = r.tm_min;
4730 lpSystemTime->wHour = r.tm_hour;
4732 lpSystemTime->wMonth = 13 - r.tm_mon;
4734 if (lpSystemTime->wMonth == 1)
4735 lpSystemTime->wMonth = 12;
4736 else
4737 lpSystemTime->wMonth--;
4739 lpSystemTime->wYear = 1899 - (r.tm_year - 1900);
4741 if (!isleap(lpSystemTime->wYear) )
4742 lpSystemTime->wDay = Days_Per_Month[13 - lpSystemTime->wMonth] - r.tm_mday;
4743 else
4744 lpSystemTime->wDay = Days_Per_Month_LY[13 - lpSystemTime->wMonth] - r.tm_mday;
4749 if (!isleap(lpSystemTime->wYear))
4752 (Century_Code+Month_Code+Year_Code+Day) % 7
4754 The century code repeats every 400 years , so the array
4755 works out like this,
4757 Century_Code[0] is for 16th/20th Centry
4758 Century_Code[1] is for 17th/21th Centry
4759 Century_Code[2] is for 18th/22th Centry
4760 Century_Code[3] is for 19th/23th Centry
4762 The year code is found with the formula (year + (year / 4))
4763 the "year" must be between 0 and 99 .
4765 The Month Code (Month_Code[1]) starts with January and
4766 ends with December.
4769 lpSystemTime->wDayOfWeek = (
4770 Century_Code[(( (lpSystemTime->wYear+100) - lpSystemTime->wYear%100) /100) %4]+
4771 ((lpSystemTime->wYear%100)+(lpSystemTime->wYear%100)/4)+
4772 Month_Code[lpSystemTime->wMonth]+
4773 lpSystemTime->wDay) % 7;
4775 if (lpSystemTime->wDayOfWeek == 0) lpSystemTime->wDayOfWeek = 7;
4776 else lpSystemTime->wDayOfWeek -= 1;
4778 else
4780 lpSystemTime->wDayOfWeek = (
4781 Century_Code[(((lpSystemTime->wYear+100) - lpSystemTime->wYear%100)/100)%4]+
4782 ((lpSystemTime->wYear%100)+(lpSystemTime->wYear%100)/4)+
4783 Month_Code_LY[lpSystemTime->wMonth]+
4784 lpSystemTime->wDay) % 7;
4786 if (lpSystemTime->wDayOfWeek == 0) lpSystemTime->wDayOfWeek = 7;
4787 else lpSystemTime->wDayOfWeek -= 1;
4790 t = floor(vtime);
4791 timeofday = vtime - t;
4793 lpSystemTime->wMilliseconds = (timeofday
4794 - lpSystemTime->wHour*(1/24)
4795 - lpSystemTime->wMinute*(1/1440)
4796 - lpSystemTime->wSecond*(1/86400) )*(1/5184000);
4798 return 1;
4801 /***********************************************************************
4802 * VarUdateFromDate [OLEAUT32.331]
4804 HRESULT WINAPI VarUdateFromDate( DATE datein, ULONG dwFlags, UDATE *pudateout)
4806 HRESULT i = 0;
4807 static const BYTE Days_Per_Month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4808 static const BYTE Days_Per_Month_LY[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4810 TRACE("DATE = %f\n", (double)datein);
4811 i = VariantTimeToSystemTime(datein, &(pudateout->st) );
4813 if (i)
4815 pudateout->wDayOfYear = 0;
4817 if (isleap(pudateout->st.wYear))
4819 for (i =1; i<pudateout->st.wMonth; i++)
4820 pudateout->wDayOfYear += Days_Per_Month[i];
4822 else
4824 for (i =1; i<pudateout->st.wMonth; i++)
4825 pudateout->wDayOfYear += Days_Per_Month_LY[i];
4828 pudateout->wDayOfYear += pudateout->st.wDay;
4829 dwFlags = 0; /*VAR_VALIDDATE*/
4831 else dwFlags = 0;
4833 return i;
4836 /***********************************************************************
4837 * VarDateFromUdate [OLEAUT32.330]
4839 HRESULT WINAPI VarDateFromUdate(UDATE *pudateout,
4840 ULONG dwFlags, DATE *datein)
4842 HRESULT i;
4843 double t = 0;
4844 TRACE(" %d/%d/%d %d:%d:%d\n",
4845 pudateout->st.wMonth, pudateout->st.wDay,
4846 pudateout->st.wYear, pudateout->st.wHour,
4847 pudateout->st.wMinute, pudateout->st.wSecond);
4850 i = SystemTimeToVariantTime(&(pudateout->st), &t);
4851 *datein = t;
4853 if (i) return S_OK;
4854 else return E_INVALIDARG;
4858 /**********************************************************************
4859 * VarBstrCmp [OLEAUT32.440]
4861 * flags can be:
4862 * NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS
4863 * NORM_IGNORESTRINGWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA
4866 HRESULT WINAPI VarBstrCmp(BSTR left, BSTR right, LCID lcid, DWORD flags)
4868 DWORD r;
4870 TRACE("( %s %s %ld %lx ) partial stub\n", debugstr_w(left), debugstr_w(right), lcid, flags);
4872 /* Contrary to the MSDN, this returns eq for null vs null, null vs L"" and L"" vs NULL */
4873 if((!left) || (!right)) {
4875 if (!left && (!right || *right==0)) return VARCMP_EQ;
4876 else if (!right && (!left || *left==0)) return VARCMP_EQ;
4877 else return VARCMP_NULL;
4880 if(flags&NORM_IGNORECASE)
4881 r = lstrcmpiW(left,right);
4882 else
4883 r = lstrcmpW(left,right);
4885 if(r<0)
4886 return VARCMP_LT;
4887 if(r>0)
4888 return VARCMP_GT;
4890 return VARCMP_EQ;
4893 /**********************************************************************
4894 * VarBstrCat [OLEAUT32.439]
4896 HRESULT WINAPI VarBstrCat(BSTR left, BSTR right, BSTR *out)
4898 BSTR result;
4900 TRACE("( %s %s %p )\n", debugstr_w(left), debugstr_w(right), out);
4902 if( (!left) || (!right) || (!out) )
4903 return 0;
4905 result = SysAllocStringLen(left, lstrlenW(left)+lstrlenW(right));
4906 lstrcatW(result,right);
4908 *out = result;
4910 return 1;
4913 /**********************************************************************
4914 * VarCat [OLEAUT32.441]
4916 HRESULT WINAPI VarCat(LPVARIANT left, LPVARIANT right, LPVARIANT out)
4918 /* Should we VariantClear out? */
4919 /* Can we handle array, vector, by ref etc. */
4920 if ((V_VT(left)&VT_TYPEMASK) == VT_NULL &&
4921 (V_VT(right)&VT_TYPEMASK) == VT_NULL)
4923 V_VT(out) = VT_NULL;
4924 return S_OK;
4926 else if (V_VT(left) == VT_BSTR && V_VT(right) == VT_BSTR)
4928 V_VT(out) = VT_BSTR;
4929 VarBstrCat (V_BSTR(left), V_BSTR(right), &V_BSTR(out));
4930 return S_OK;
4932 else
4933 FIXME ("types not supported\n");
4934 return S_OK;
4937 /**********************************************************************
4938 * VarCmp [OLEAUT32.442]
4940 * flags can be:
4941 * NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS
4942 * NORM_IGNOREWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA
4945 HRESULT WINAPI VarCmp(LPVARIANT left, LPVARIANT right, LCID lcid, DWORD flags)
4949 BOOL lOk = TRUE;
4950 BOOL rOk = TRUE;
4951 LONGLONG lVal = -1;
4952 LONGLONG rVal = -1;
4954 TRACE("Left Var:\n");
4955 dump_Variant(left);
4956 TRACE("Right Var:\n");
4957 dump_Variant(right);
4959 /* If either are null, then return VARCMP_NULL */
4960 if ((V_VT(left)&VT_TYPEMASK) == VT_NULL ||
4961 (V_VT(right)&VT_TYPEMASK) == VT_NULL)
4962 return VARCMP_NULL;
4964 /* Strings - use VarBstrCmp */
4965 if ((V_VT(left)&VT_TYPEMASK) == VT_BSTR &&
4966 (V_VT(right)&VT_TYPEMASK) == VT_BSTR) {
4967 return VarBstrCmp(V_BSTR(left), V_BSTR(right), lcid, flags);
4970 /* Integers - Ideally like to use VarDecCmp, but no Dec support yet
4971 Use LONGLONG to maximize ranges */
4972 lOk = TRUE;
4973 switch (V_VT(left)&VT_TYPEMASK) {
4974 case VT_I1 : lVal = V_UNION(left,cVal); break;
4975 case VT_I2 : lVal = V_UNION(left,iVal); break;
4976 case VT_I4 : lVal = V_UNION(left,lVal); break;
4977 case VT_INT : lVal = V_UNION(left,lVal); break;
4978 case VT_UI1 : lVal = V_UNION(left,bVal); break;
4979 case VT_UI2 : lVal = V_UNION(left,uiVal); break;
4980 case VT_UI4 : lVal = V_UNION(left,ulVal); break;
4981 case VT_UINT : lVal = V_UNION(left,ulVal); break;
4982 default: lOk = FALSE;
4985 rOk = TRUE;
4986 switch (V_VT(right)&VT_TYPEMASK) {
4987 case VT_I1 : rVal = V_UNION(right,cVal); break;
4988 case VT_I2 : rVal = V_UNION(right,iVal); break;
4989 case VT_I4 : rVal = V_UNION(right,lVal); break;
4990 case VT_INT : rVal = V_UNION(right,lVal); break;
4991 case VT_UI1 : rVal = V_UNION(right,bVal); break;
4992 case VT_UI2 : rVal = V_UNION(right,uiVal); break;
4993 case VT_UI4 : rVal = V_UNION(right,ulVal); break;
4994 case VT_UINT : rVal = V_UNION(right,ulVal); break;
4995 default: rOk = FALSE;
4998 if (lOk && rOk) {
4999 if (lVal < rVal) {
5000 return VARCMP_LT;
5001 } else if (lVal > rVal) {
5002 return VARCMP_GT;
5003 } else {
5004 return VARCMP_EQ;
5008 /* Strings - use VarBstrCmp */
5009 if ((V_VT(left)&VT_TYPEMASK) == VT_DATE &&
5010 (V_VT(right)&VT_TYPEMASK) == VT_DATE) {
5012 if (floor(V_UNION(left,date)) == floor(V_UNION(right,date))) {
5013 /* Due to floating point rounding errors, calculate varDate in whole numbers) */
5014 double wholePart = 0.0;
5015 double leftR;
5016 double rightR;
5018 /* Get the fraction * 24*60*60 to make it into whole seconds */
5019 wholePart = (double) floor( V_UNION(left,date) );
5020 if (wholePart == 0) wholePart = 1;
5021 leftR = floor(fmod( V_UNION(left,date), wholePart ) * (24*60*60));
5023 wholePart = (double) floor( V_UNION(right,date) );
5024 if (wholePart == 0) wholePart = 1;
5025 rightR = floor(fmod( V_UNION(right,date), wholePart ) * (24*60*60));
5027 if (leftR < rightR) {
5028 return VARCMP_LT;
5029 } else if (leftR > rightR) {
5030 return VARCMP_GT;
5031 } else {
5032 return VARCMP_EQ;
5035 } else if (V_UNION(left,date) < V_UNION(right,date)) {
5036 return VARCMP_LT;
5037 } else if (V_UNION(left,date) > V_UNION(right,date)) {
5038 return VARCMP_GT;
5043 FIXME("VarCmp partial implementation, doesnt support these pair of variant types");
5044 return E_FAIL;
5047 /**********************************************************************
5048 * VarAnd [OLEAUT32.438]
5051 HRESULT WINAPI VarAnd(LPVARIANT left, LPVARIANT right, LPVARIANT result)
5053 HRESULT rc = E_FAIL;
5056 TRACE("Left Var:\n");
5057 dump_Variant(left);
5058 TRACE("Right Var:\n");
5059 dump_Variant(right);
5061 if ((V_VT(left)&VT_TYPEMASK) == VT_BOOL &&
5062 (V_VT(right)&VT_TYPEMASK) == VT_BOOL) {
5064 V_VT(result) = VT_BOOL;
5065 if (V_BOOL(left) && V_BOOL(right)) {
5066 V_BOOL(result) = VARIANT_TRUE;
5067 } else {
5068 V_BOOL(result) = VARIANT_FALSE;
5070 rc = S_OK;
5072 } else {
5073 FIXME("VarAnd stub\n");
5076 TRACE("rc=%d, Result:\n", (int) rc);
5077 dump_Variant(result);
5078 return rc;
5081 /**********************************************************************
5082 * VarNot [OLEAUT32.482]
5085 HRESULT WINAPI VarNot(LPVARIANT in, LPVARIANT result)
5087 HRESULT rc = E_FAIL;
5089 TRACE("Var In:\n");
5090 dump_Variant(in);
5092 if ((V_VT(in)&VT_TYPEMASK) == VT_BOOL) {
5094 V_VT(result) = VT_BOOL;
5095 if (V_BOOL(in)) {
5096 V_BOOL(result) = VARIANT_FALSE;
5097 } else {
5098 V_BOOL(result) = VARIANT_TRUE;
5100 rc = S_OK;
5102 } else {
5103 FIXME("VarNot stub\n");
5106 TRACE("rc=%d, Result:\n", (int) rc);
5107 dump_Variant(result);
5108 return rc;
5111 /**********************************************************************
5112 * VarTokenizeFormatString [OLEAUT32.490]
5114 * From investigation on W2K, a list is built up which is:
5116 * <0x00> AA BB - Copy from AA for BB chars (Note 1 byte with wrap!)
5117 * <token> - Insert appropriate token
5120 HRESULT VarTokenizeFormatString(LPOLESTR format, LPBYTE rgbTok,
5121 int cbTok, int iFirstDay, int iFirstWeek,
5122 LCID lcid, int *pcbActual) {
5124 FORMATHDR *hdr;
5125 int realLen, formatLeft;
5126 BYTE *pData;
5127 LPSTR pFormatA, pStart;
5128 int checkStr;
5129 BOOL insertCopy = FALSE;
5130 LPSTR copyFrom = NULL;
5132 TRACE("'%s', %p %d %d %d only date support\n", debugstr_w(format), rgbTok, cbTok,
5133 iFirstDay, iFirstWeek);
5135 /* Big enough for header? */
5136 if (cbTok < sizeof(FORMATHDR)) {
5137 return TYPE_E_BUFFERTOOSMALL;
5140 /* Insert header */
5141 hdr = (FORMATHDR *) rgbTok;
5142 memset(hdr, 0x00, sizeof(FORMATHDR));
5143 hdr->hex3 = 0x03; /* No idea what these are */
5144 hdr->hex6 = 0x06;
5146 /* Start parsing string */
5147 realLen = sizeof(FORMATHDR);
5148 pData = rgbTok + realLen;
5149 pFormatA = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
5150 pStart = pFormatA;
5151 formatLeft = strlen(pFormatA);
5153 /* Work through the format */
5154 while (*pFormatA != 0x00) {
5156 checkStr = 0;
5157 while (checkStr>=0 && (formatTokens[checkStr].tokenSize != 0x00)) {
5158 if (formatLeft >= formatTokens[checkStr].tokenSize &&
5159 strncmp(formatTokens[checkStr].str, pFormatA,
5160 formatTokens[checkStr].tokenSize) == 0) {
5161 TRACE("match on '%s'\n", formatTokens[checkStr].str);
5163 /* Found Match! */
5165 /* If we have skipped chars, insert the copy */
5166 if (insertCopy == TRUE) {
5168 if ((realLen + 3) > cbTok) {
5169 HeapFree( GetProcessHeap(), 0, pFormatA );
5170 return TYPE_E_BUFFERTOOSMALL;
5172 insertCopy = FALSE;
5173 *pData = TOK_COPY;
5174 pData++;
5175 *pData = (BYTE)(copyFrom - pStart);
5176 pData++;
5177 *pData = (BYTE)(pFormatA - copyFrom);
5178 pData++;
5179 realLen = realLen + 3;
5183 /* Now insert the token itself */
5184 if ((realLen + 1) > cbTok) {
5185 HeapFree( GetProcessHeap(), 0, pFormatA );
5186 return TYPE_E_BUFFERTOOSMALL;
5188 *pData = formatTokens[checkStr].tokenId;
5189 pData = pData + 1;
5190 realLen = realLen + 1;
5192 pFormatA = pFormatA + formatTokens[checkStr].tokenSize;
5193 formatLeft = formatLeft - formatTokens[checkStr].tokenSize;
5194 checkStr = -1; /* Flag as found and break out of while loop */
5195 } else {
5196 checkStr++;
5200 /* Did we ever match a token? */
5201 if (checkStr != -1 && insertCopy == FALSE) {
5202 TRACE("No match - need to insert copy from %p [%p]\n", pFormatA, pStart);
5203 insertCopy = TRUE;
5204 copyFrom = pFormatA;
5205 } else if (checkStr != -1) {
5206 pFormatA = pFormatA + 1;
5211 /* Finally, if we have skipped chars, insert the copy */
5212 if (insertCopy == TRUE) {
5214 TRACE("Chars left over, so still copy %p,%p,%p\n", copyFrom, pStart, pFormatA);
5215 if ((realLen + 3) > cbTok) {
5216 HeapFree( GetProcessHeap(), 0, pFormatA );
5217 return TYPE_E_BUFFERTOOSMALL;
5219 insertCopy = FALSE;
5220 *pData = TOK_COPY;
5221 pData++;
5222 *pData = (BYTE)(copyFrom - pStart);
5223 pData++;
5224 *pData = (BYTE)(pFormatA - copyFrom);
5225 pData++;
5226 realLen = realLen + 3;
5229 /* Finally insert the terminator */
5230 if ((realLen + 1) > cbTok) {
5231 HeapFree( GetProcessHeap(), 0, pFormatA );
5232 return TYPE_E_BUFFERTOOSMALL;
5234 *pData++ = TOK_END;
5235 realLen = realLen + 1;
5237 /* Finally fill in the length */
5238 hdr->len = realLen;
5239 *pcbActual = realLen;
5241 #if 0
5242 { int i,j;
5243 for (i=0; i<realLen; i=i+0x10) {
5244 printf(" %4.4x : ", i);
5245 for (j=0; j<0x10 && (i+j < realLen); j++) {
5246 printf("%2.2x ", rgbTok[i+j]);
5248 printf("\n");
5251 #endif
5252 HeapFree( GetProcessHeap(), 0, pFormatA );
5254 return S_OK;
5257 /**********************************************************************
5258 * VarFormatFromTokens [OLEAUT32.472]
5259 * FIXME: No account of flags or iFirstDay etc
5261 HRESULT VarFormatFromTokens(LPVARIANT varIn, LPOLESTR format,
5262 LPBYTE pbTokCur, ULONG dwFlags, BSTR *pbstrOut,
5263 LCID lcid) {
5265 FORMATHDR *hdr = (FORMATHDR *)pbTokCur;
5266 BYTE *pData = pbTokCur + sizeof (FORMATHDR);
5267 LPSTR pFormatA = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
5268 char output[BUFFER_MAX];
5269 char *pNextPos;
5270 int size, whichToken;
5271 VARIANTARG Variant;
5272 struct tm TM;
5276 TRACE("'%s', %p %lx %p only date support\n", pFormatA, pbTokCur, dwFlags, pbstrOut);
5277 TRACE("varIn:\n");
5278 dump_Variant(varIn);
5280 memset(output, 0x00, BUFFER_MAX);
5281 pNextPos = output;
5283 while (*pData != TOK_END && ((pData - pbTokCur) <= (hdr->len))) {
5285 TRACE("Output looks like : '%s'\n", output);
5287 /* Convert varient to appropriate data type */
5288 whichToken = 0;
5289 while ((formatTokens[whichToken].tokenSize != 0x00) &&
5290 (formatTokens[whichToken].tokenId != *pData)) {
5291 whichToken++;
5294 /* Use Variant local from here downwards as always correct type */
5295 if (formatTokens[whichToken].tokenSize > 0 &&
5296 formatTokens[whichToken].varTypeRequired != 0) {
5297 VariantInit( &Variant );
5298 if (Coerce( &Variant, lcid, dwFlags, varIn,
5299 formatTokens[whichToken].varTypeRequired ) != S_OK) {
5300 HeapFree( GetProcessHeap(), 0, pFormatA );
5301 return DISP_E_TYPEMISMATCH;
5302 } else if (formatTokens[whichToken].varTypeRequired == VT_DATE) {
5303 if( DateToTm( V_UNION(&Variant,date), dwFlags, &TM ) == FALSE ) {
5304 HeapFree( GetProcessHeap(), 0, pFormatA );
5305 return E_INVALIDARG;
5310 TRACE("Looking for match on token '%x'\n", *pData);
5311 switch (*pData) {
5312 case TOK_COPY:
5313 TRACE("Copy from %d for %d bytes\n", *(pData+1), *(pData+2));
5314 memcpy(pNextPos, &pFormatA[*(pData+1)], *(pData+2));
5315 pNextPos = pNextPos + *(pData+2);
5316 pData = pData + 3;
5317 break;
5319 case TOK_COLON :
5320 /* Get locale information - Time Seperator */
5321 size = GetLocaleInfoA(lcid, LOCALE_STIME, NULL, 0);
5322 GetLocaleInfoA(lcid, LOCALE_STIME, pNextPos, size);
5323 TRACE("TOK_COLON Time seperator is '%s'\n", pNextPos);
5324 pNextPos = pNextPos + size;
5325 pData = pData + 1;
5326 break;
5328 case TOK_SLASH :
5329 /* Get locale information - Date Seperator */
5330 size = GetLocaleInfoA(lcid, LOCALE_SDATE, NULL, 0);
5331 GetLocaleInfoA(lcid, LOCALE_SDATE, pNextPos, size);
5332 TRACE("TOK_COLON Time seperator is '%s'\n", pNextPos);
5333 pNextPos = pNextPos + size;
5334 pData = pData + 1;
5335 break;
5337 case TOK_d :
5338 sprintf(pNextPos, "%d", TM.tm_mday);
5339 pNextPos = pNextPos + strlen(pNextPos);
5340 pData = pData + 1;
5341 break;
5343 case TOK_dd :
5344 sprintf(pNextPos, "%2.2d", TM.tm_mday);
5345 pNextPos = pNextPos + strlen(pNextPos);
5346 pData = pData + 1;
5347 break;
5349 case TOK_w :
5350 sprintf(pNextPos, "%d", TM.tm_wday+1);
5351 pNextPos = pNextPos + strlen(pNextPos);
5352 pData = pData + 1;
5353 break;
5355 case TOK_m :
5356 sprintf(pNextPos, "%d", TM.tm_mon+1);
5357 pNextPos = pNextPos + strlen(pNextPos);
5358 pData = pData + 1;
5359 break;
5361 case TOK_mm :
5362 sprintf(pNextPos, "%2.2d", TM.tm_mon+1);
5363 pNextPos = pNextPos + strlen(pNextPos);
5364 pData = pData + 1;
5365 break;
5367 case TOK_q :
5368 sprintf(pNextPos, "%d", ((TM.tm_mon+1)/4)+1);
5369 pNextPos = pNextPos + strlen(pNextPos);
5370 pData = pData + 1;
5371 break;
5373 case TOK_y :
5374 sprintf(pNextPos, "%2.2d", TM.tm_yday+1);
5375 pNextPos = pNextPos + strlen(pNextPos);
5376 pData = pData + 1;
5377 break;
5379 case TOK_yy :
5380 sprintf(pNextPos, "%2.2d", TM.tm_year);
5381 pNextPos = pNextPos + strlen(pNextPos);
5382 pData = pData + 1;
5383 break;
5385 case TOK_yyyy :
5386 sprintf(pNextPos, "%4.4d", TM.tm_year);
5387 pNextPos = pNextPos + strlen(pNextPos);
5388 pData = pData + 1;
5389 break;
5391 case TOK_h :
5392 sprintf(pNextPos, "%d", TM.tm_hour);
5393 pNextPos = pNextPos + strlen(pNextPos);
5394 pData = pData + 1;
5395 break;
5397 case TOK_Hh :
5398 sprintf(pNextPos, "%2.2d", TM.tm_hour);
5399 pNextPos = pNextPos + strlen(pNextPos);
5400 pData = pData + 1;
5401 break;
5403 case TOK_N :
5404 sprintf(pNextPos, "%d", TM.tm_min);
5405 pNextPos = pNextPos + strlen(pNextPos);
5406 pData = pData + 1;
5407 break;
5409 case TOK_Nn :
5410 sprintf(pNextPos, "%2.2d", TM.tm_min);
5411 pNextPos = pNextPos + strlen(pNextPos);
5412 pData = pData + 1;
5413 break;
5415 case TOK_S :
5416 sprintf(pNextPos, "%d", TM.tm_sec);
5417 pNextPos = pNextPos + strlen(pNextPos);
5418 pData = pData + 1;
5419 break;
5421 case TOK_Ss :
5422 sprintf(pNextPos, "%2.2d", TM.tm_sec);
5423 pNextPos = pNextPos + strlen(pNextPos);
5424 pData = pData + 1;
5425 break;
5427 /* FIXME: To Do! */
5428 case TOK_ttttt :
5429 case TOK_AMsPM :
5430 case TOK_amspm :
5431 case TOK_AsP :
5432 case TOK_asp :
5433 case TOK_AMPM :
5434 case TOK_c :
5435 case TOK_ddd :
5436 case TOK_dddd :
5437 case TOK_ddddd :
5438 case TOK_dddddd :
5439 case TOK_ww :
5440 case TOK_mmm :
5441 case TOK_mmmm :
5442 default:
5443 FIXME("Unhandled token for VarFormat %d\n", *pData);
5444 HeapFree( GetProcessHeap(), 0, pFormatA );
5445 return E_INVALIDARG;
5450 *pbstrOut = StringDupAtoBstr( output );
5451 HeapFree( GetProcessHeap(), 0, pFormatA );
5452 return S_OK;
5455 /**********************************************************************
5456 * VarFormat [OLEAUT32.469]
5459 HRESULT WINAPI VarFormat(LPVARIANT varIn, LPOLESTR format,
5460 int firstDay, int firstWeek, ULONG dwFlags,
5461 BSTR *pbstrOut) {
5463 LPSTR pNewString = NULL;
5464 HRESULT rc = S_OK;
5466 TRACE("mostly stub! format='%s' day=%d, wk=%d, flags=%ld\n",
5467 debugstr_w(format), firstDay, firstWeek, dwFlags);
5468 TRACE("varIn:\n");
5469 dump_Variant(varIn);
5471 /* Get format string */
5472 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
5474 /* FIXME: Handle some simple pre-definted format strings : */
5475 if (((V_VT(varIn)&VT_TYPEMASK) == VT_CY) && (lstrcmpiA(pNewString, "Currency") == 0)) {
5477 /* Can't use VarBstrFromCy as it does not put currency sign on nor decimal places */
5478 double curVal;
5479 rc = VarR8FromCy(V_UNION(varIn,cyVal), &curVal);
5480 if (rc == S_OK) {
5481 char tmpStr[BUFFER_MAX];
5482 sprintf(tmpStr, "%f", curVal);
5483 if (GetCurrencyFormatA(GetUserDefaultLCID(), dwFlags, tmpStr, NULL, pBuffer, BUFFER_MAX) == 0) {
5484 return E_FAIL;
5485 } else {
5486 *pbstrOut = StringDupAtoBstr( pBuffer );
5490 } else if ((V_VT(varIn)&VT_TYPEMASK) == VT_DATE) {
5492 /* Attempt to do proper formatting! */
5493 int firstToken = -1;
5495 rc = VarTokenizeFormatString(format, pBuffer, sizeof(pBuffer), firstDay,
5496 firstWeek, GetUserDefaultLCID(), &firstToken);
5497 if (rc==S_OK) {
5498 rc = VarFormatFromTokens(varIn, format, pBuffer, dwFlags, pbstrOut, GetUserDefaultLCID());
5502 } else {
5503 FIXME("Unsupported format!\n");
5504 *pbstrOut = StringDupAtoBstr( "??" );
5507 /* Free allocated storage */
5508 HeapFree( GetProcessHeap(), 0, pNewString );
5509 TRACE("result: '%s'\n", debugstr_w(*pbstrOut));
5510 return rc;