source: trunk/src/oleaut32/variant.c

Last change on this file was 21916, checked in by dmik, 14 years ago

Merge branch gcc-kmk to trunk.

File size: 147.1 KB
RevLine 
[4837]1/*
2 * VARIANT
3 *
4 * Copyright 1998 Jean-Claude Cote
5 *
[8450]6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
[4837]20 * NOTES
21 * This implements the low-level and hi-level APIs for manipulating VARIANTs.
22 * The low-level APIs are used to do data coercion between different data types.
23 * The hi-level APIs are built on top of these low-level APIs and handle
24 * initialization, copying, destroying and changing the type of VARIANTs.
25 *
26 * TODO:
27 * - The Variant APIs do not support international languages, currency
28 * types, number formating and calendar. They only support U.S. English format.
29 * - The Variant APIs do not the following types: IUknown, IDispatch, DECIMAL and SafeArray.
30 * The prototypes for these are commented out in the oleauto.h file. They need
31 * to be implemented and cases need to be added to the switches of the existing APIs.
32 * - The parsing of date for the VarDateFromStr is not complete.
33 * - The date manipulations do not support dates prior to 1900.
34 * - The parsing does not accept as many formats as the Windows implementation.
35 */
[5840]36
[4837]37#include "config.h"
[9400]38
[4837]39#include <string.h>
40#include <stdlib.h>
41#include <stdio.h>
42#include <math.h>
43#include <time.h>
44
45#ifdef HAVE_FLOAT_H
46# include <float.h>
47#endif
48
49#include "windef.h"
50#include "oleauto.h"
51#include "heap.h"
[8450]52#include "wine/debug.h"
[4837]53#include "winerror.h"
54#include "parsedt.h"
[9400]55#include "typelib.h"
[4837]56
[8450]57WINE_DEFAULT_DEBUG_CHANNEL(ole);
[4837]58
[6944]59#define SYSDUPSTRING(str) SysAllocStringLen((str), SysStringLen(str))
60
[4837]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
68
69#undef CHAR_MAX
70#undef CHAR_MIN
71static const char CHAR_MAX = 127;
72static const char CHAR_MIN = -128;
73static const BYTE UI1_MAX = 255;
74static const BYTE UI1_MIN = 0;
75static const unsigned short UI2_MAX = 65535;
76static const unsigned short UI2_MIN = 0;
77static const short I2_MAX = 32767;
78static const short I2_MIN = -32768;
79static const unsigned long UI4_MAX = 4294967295U;
80static const unsigned long UI4_MIN = 0;
81static const long I4_MAX = 2147483647;
82static const long I4_MIN = -(2147483648U);
83static const DATE DATE_MIN = -657434;
84static const DATE DATE_MAX = 2958465;
85
86
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.
90 */
91#define PROCESSING_INNER_VARIANT 0x0001
92
93/* General use buffer.
94 */
95#define BUFFER_MAX 1024
96static char pBuffer[BUFFER_MAX];
97
98/*
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.
102 */
[9400]103
104/*
105 * Use 365 days/year and a manual calculation for leap year days
106 * to keep arithmetic simple
[4837]107 */
[9400]108static const double DAYS_IN_ONE_YEAR = 365.0;
109
110/*
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
[4837]114 *
115 */
[9400]116/* Pre defined tokens */
117#define TOK_COPY 0x00
118#define TOK_END 0x02
119#define LARGEST_TOKENID 6
[4837]120
[9400]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
[6944]154
[9400]155typedef struct tagFORMATTOKEN {
156 char *str;
157 BYTE tokenSize;
158 BYTE tokenId;
159 int varTypeRequired;
160} FORMATTOKEN;
161
162typedef struct tagFORMATHDR {
163 BYTE len;
164 BYTE hex3;
165 BYTE hex6;
166 BYTE reserved[8];
167} FORMATHDR;
168
169FORMATTOKEN 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}
202};
203
[4837]204/******************************************************************************
[6711]205 * DateTimeStringToTm [INTERNAL]
[4837]206 *
207 * Converts a string representation of a date and/or time to a tm structure.
208 *
209 * Note this function uses the postgresql date parsing functions found
210 * in the parsedt.c file.
211 *
212 * Returns TRUE if successful.
213 *
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.
217 *
218 ******************************************************************************/
[6575]219static BOOL DateTimeStringToTm( OLECHAR* strIn, DWORD dwFlags, struct tm* pTm )
[4837]220{
[6711]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;
[4837]230
[6711]231 /* Convert the string to ASCII since this is the only format
232 * postgesql can handle.
233 */
234 strDateTime = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
[4837]235
[6711]236 if( strDateTime != NULL )
237 {
238 /* Make sure we don't go over the maximum length
239 * accepted by postgesql.
240 */
241 if( strlen( strDateTime ) <= MAXDATELEN )
242 {
243 if( ParseDateTime( strDateTime, lowstr, field, ftype, MAXDATEFIELDS, &nf) == 0 )
244 {
245 if( dwFlags & VAR_DATEVALUEONLY )
246 {
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.
251 */
252 if( DecodeDateTime(field, ftype, nf, &dtype, pTm, &fsec, &tzp) == 0 )
253 {
254 /* Eliminate the time information since we
255 * were asked to get date information only.
256 */
257 pTm->tm_sec = 0;
258 pTm->tm_min = 0;
259 pTm->tm_hour = 0;
260 res = TRUE;
261 }
262 }
263 if( dwFlags & VAR_TIMEVALUEONLY )
264 {
265 /* Get time information only.
266 */
267 if( DecodeTimeOnly(field, ftype, nf, &dtype, pTm, &fsec) == 0 )
268 {
269 res = TRUE;
270 }
271 }
272 else
273 {
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.
278 */
279 if( DecodeDateTime(field, ftype, nf, &dtype, pTm, &fsec, &tzp) != -1 )
280 {
281 res = TRUE;
282 }
283 }
284 }
285 }
286 HeapFree( GetProcessHeap(), 0, strDateTime );
287 }
[4837]288
[6711]289 return res;
[4837]290}
291
292
293
294
295
296
297/******************************************************************************
[6711]298 * TmToDATE [INTERNAL]
[4837]299 *
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 {
[6711]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 * };
[4837]325 *
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.
329 *
330 * Returns TRUE if successful.
331 */
332static BOOL TmToDATE( struct tm* pTm, DATE *pDateOut )
333{
[6944]334 int leapYear = 0;
[4837]335
[9400]336 /* Hmmm... An uninitialized Date in VB is December 30 1899 so
337 Start at 0. This is the way DATE is defined. */
[4837]338
[6944]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.
343 */
344 *pDateOut = 1;
[4837]345
[9400]346 if( (pTm->tm_year - 1900) >= 0 ) {
[6944]347
[9400]348 /* Add the number of days corresponding to
349 * tm_year.
350 */
351 *pDateOut += (pTm->tm_year - 1900) * 365;
[6944]352
[9400]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
358 */
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 );
[6944]362
[9400]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.
367 */
368 if( isleap( pTm->tm_year ) )
369 leapYear = 1;
370
371 /* Add the number of days corresponding to
372 * the month. (remember tm_mon is 0..11)
373 */
374 switch( pTm->tm_mon )
375 {
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;
409 }
410 /* Add the number of days in this month.
411 */
412 *pDateOut += pTm->tm_mday;
413
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.
417 */
418 } else {
419 *pDateOut = 0;
[6944]420 }
421
422 *pDateOut += pTm->tm_hour / 24.0;
423 *pDateOut += pTm->tm_min / 1440.0;
424 *pDateOut += pTm->tm_sec / 86400.0;
425 return TRUE;
[4837]426}
427
428/******************************************************************************
[6711]429 * DateToTm [INTERNAL]
[4837]430 *
431 * This function converts a windows DATE to a tm structure.
432 *
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.
436 *
437 * Note this function does not support dates before the January 1, 1900
438 * or ( dateIn < 2.0 ).
439 *
440 * Returns TRUE if successful.
441 */
[9400]442BOOL DateToTm( DATE dateIn, DWORD dwFlags, struct tm* pTm )
[4837]443{
[6944]444 double decimalPart = 0.0;
445 double wholePart = 0.0;
[4837]446
[6944]447 memset(pTm,0,sizeof(*pTm));
[4837]448
[6944]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.
455 */
[9400]456 decimalPart = fmod( dateIn, 1.0 ); /* Do this before the -1, otherwise 0.xx goes negative */
[6944]457 dateIn -= 1.0;
458 wholePart = (double) floor( dateIn );
459
460 if( !(dwFlags & VAR_TIMEVALUEONLY) )
461 {
[9400]462 unsigned int nDay = 0;
[6944]463 int leapYear = 0;
464 double yearsSince1900 = 0;
465
[9400]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;
476 }
477
478 } else {
479
480 /* Start at 1900, this is where the DATE time 0.0 starts.
481 */
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.
485 */
486 yearsSince1900 = floor( (wholePart / DAYS_IN_ONE_YEAR) + 0.001 );
487 pTm->tm_year += yearsSince1900;
488 /* determine if this is a leap year.
489 */
490 if( isleap( pTm->tm_year ) )
491 {
492 leapYear = 1;
493 wholePart++;
494 }
495
496 /* find what day of that year the "wholePart" corresponds to.
497 * Note: nDay is in [1-366] format
498 */
499 nDay = (((unsigned int) wholePart) - ((pTm->tm_year-1900) * DAYS_IN_ONE_YEAR ));
500
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
506 */
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 );
510
511 /* Set the tm_yday value.
512 * Note: The day must be converted from [1-366] to [0-365]
513 */
514 /*pTm->tm_yday = nDay - 1;*/
515 /* find which month this day corresponds to.
516 */
517 if( nDay <= 31 )
518 {
519 pTm->tm_mday = nDay;
520 pTm->tm_mon = 0;
521 }
522 else if( nDay <= ( 59 + leapYear ) )
523 {
524 pTm->tm_mday = nDay - 31;
525 pTm->tm_mon = 1;
526 }
527 else if( nDay <= ( 90 + leapYear ) )
528 {
529 pTm->tm_mday = nDay - ( 59 + leapYear );
530 pTm->tm_mon = 2;
531 }
532 else if( nDay <= ( 120 + leapYear ) )
533 {
534 pTm->tm_mday = nDay - ( 90 + leapYear );
535 pTm->tm_mon = 3;
536 }
537 else if( nDay <= ( 151 + leapYear ) )
538 {
539 pTm->tm_mday = nDay - ( 120 + leapYear );
540 pTm->tm_mon = 4;
541 }
542 else if( nDay <= ( 181 + leapYear ) )
543 {
544 pTm->tm_mday = nDay - ( 151 + leapYear );
545 pTm->tm_mon = 5;
546 }
547 else if( nDay <= ( 212 + leapYear ) )
548 {
549 pTm->tm_mday = nDay - ( 181 + leapYear );
550 pTm->tm_mon = 6;
551 }
552 else if( nDay <= ( 243 + leapYear ) )
553 {
554 pTm->tm_mday = nDay - ( 212 + leapYear );
555 pTm->tm_mon = 7;
556 }
557 else if( nDay <= ( 273 + leapYear ) )
558 {
559 pTm->tm_mday = nDay - ( 243 + leapYear );
560 pTm->tm_mon = 8;
561 }
562 else if( nDay <= ( 304 + leapYear ) )
563 {
564 pTm->tm_mday = nDay - ( 273 + leapYear );
565 pTm->tm_mon = 9;
566 }
567 else if( nDay <= ( 334 + leapYear ) )
568 {
569 pTm->tm_mday = nDay - ( 304 + leapYear );
570 pTm->tm_mon = 10;
571 }
572 else if( nDay <= ( 365 + leapYear ) )
573 {
574 pTm->tm_mday = nDay - ( 334 + leapYear );
575 pTm->tm_mon = 11;
576 }
[6944]577 }
578 }
579 if( !(dwFlags & VAR_DATEVALUEONLY) )
580 {
581 /* find the number of seconds in this day.
582 * fractional part times, hours, minutes, seconds.
[9400]583 * Note: 0.1 is hack to ensure figures come out in whole numbers
584 * due to floating point inaccuracies
[6944]585 */
586 pTm->tm_hour = (int) ( decimalPart * 24 );
587 pTm->tm_min = (int) ( ( ( decimalPart * 24 ) - pTm->tm_hour ) * 60 );
[9400]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);
[6944]591 }
592 return TRUE;
[4837]593}
594
595
596
597/******************************************************************************
[6711]598 * SizeOfVariantData [INTERNAL]
[4837]599 *
600 * This function finds the size of the data referenced by a Variant based
601 * the type "vt" of the Variant.
602 */
603static int SizeOfVariantData( VARIANT* parg )
604{
605 int size = 0;
[6575]606 switch( V_VT(parg) & VT_TYPEMASK )
[4837]607 {
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 ):
[9400]642 case( VT_DISPATCH ):
643 case( VT_UNKNOWN ):
[4837]644 size = sizeof(void*);
645 break;
646 case( VT_CY ):
[9400]647 size = sizeof(CY);
648 break;
649 case( VT_DECIMAL ): /* hmm, tricky, DECIMAL is only VT_BYREF */
[4837]650 default:
[6575]651 FIXME("Add size information for type vt=%d\n", V_VT(parg) & VT_TYPEMASK );
[4837]652 break;
653 }
654
655 return size;
656}
657/******************************************************************************
[6711]658 * StringDupAtoBstr [INTERNAL]
[9400]659 *
[4837]660 */
661static BSTR StringDupAtoBstr( char* strIn )
662{
[6711]663 BSTR bstr = NULL;
664 OLECHAR* pNewString = NULL;
665 pNewString = HEAP_strdupAtoW( GetProcessHeap(), 0, strIn );
666 bstr = SysAllocString( pNewString );
667 HeapFree( GetProcessHeap(), 0, pNewString );
668 return bstr;
[4837]669}
670
671/******************************************************************************
[6711]672 * round [INTERNAL]
[4837]673 *
674 * Round the double value to the nearest integer value.
675 */
[21916]676static double rnd( double d )
[4837]677{
678 double decimals = 0.0, integerValue = 0.0, roundedValue = 0.0;
679 BOOL bEvenNumber = FALSE;
680 int nSign = 0;
681
682 /* Save the sign of the number
683 */
684 nSign = (d >= 0.0) ? 1 : -1;
685 d = fabs( d );
[9400]686
[6711]687 /* Remove the decimals.
688 */
[4837]689 integerValue = floor( d );
690
691 /* Set the Even flag. This is used to round the number when
692 * the decimals are exactly 1/2. If the integer part is
693 * odd the number is rounded up. If the integer part
694 * is even the number is rounded down. Using this method
695 * numbers are rounded up|down half the time.
696 */
697 bEvenNumber = (((short)fmod(integerValue, 2)) == 0) ? TRUE : FALSE;
698
699 /* Remove the integral part of the number.
700 */
701 decimals = d - integerValue;
702
[6711]703 /* Note: Ceil returns the smallest integer that is greater that x.
704 * and floor returns the largest integer that is less than or equal to x.
705 */
[4837]706 if( decimals > 0.5 )
707 {
708 /* If the decimal part is greater than 1/2
709 */
710 roundedValue = ceil( d );
711 }
712 else if( decimals < 0.5 )
713 {
714 /* If the decimal part is smaller than 1/2
715 */
716 roundedValue = floor( d );
717 }
718 else
719 {
720 /* the decimals are exactly 1/2 so round according to
721 * the bEvenNumber flag.
722 */
723 if( bEvenNumber )
724 {
725 roundedValue = floor( d );
726 }
727 else
728 {
729 roundedValue = ceil( d );
730 }
731 }
732
[6711]733 return roundedValue * nSign;
[4837]734}
735
736/******************************************************************************
[6711]737 * RemoveCharacterFromString [INTERNAL]
[4837]738 *
739 * Removes any of the characters in "strOfCharToRemove" from the "str" argument.
740 */
741static void RemoveCharacterFromString( LPSTR str, LPSTR strOfCharToRemove )
742{
[6711]743 LPSTR pNewString = NULL;
744 LPSTR strToken = NULL;
[4837]745
[6711]746 /* Check if we have a valid argument
747 */
748 if( str != NULL )
749 {
750 pNewString = strdup( str );
751 str[0] = '\0';
752 strToken = strtok( pNewString, strOfCharToRemove );
[9400]753 while( strToken != NULL ) {
[6711]754 strcat( str, strToken );
755 strToken = strtok( NULL, strOfCharToRemove );
756 }
757 free( pNewString );
758 }
759 return;
[4837]760}
761
762/******************************************************************************
[6711]763 * GetValidRealString [INTERNAL]
[4837]764 *
765 * Checks if the string is of proper format to be converted to a real value.
766 */
767static BOOL IsValidRealString( LPSTR strRealString )
768{
[6711]769 /* Real values that have a decimal point are required to either have
770 * digits before or after the decimal point. We will assume that
771 * we do not have any digits at either position. If we do encounter
772 * some we will disable this flag.
773 */
774 BOOL bDigitsRequired = TRUE;
775 /* Processed fields in the string representation of the real number.
776 */
777 BOOL bWhiteSpaceProcessed = FALSE;
778 BOOL bFirstSignProcessed = FALSE;
779 BOOL bFirstDigitsProcessed = FALSE;
780 BOOL bDecimalPointProcessed = FALSE;
781 BOOL bSecondDigitsProcessed = FALSE;
782 BOOL bExponentProcessed = FALSE;
783 BOOL bSecondSignProcessed = FALSE;
784 BOOL bThirdDigitsProcessed = FALSE;
785 /* Assume string parameter "strRealString" is valid and try to disprove it.
786 */
787 BOOL bValidRealString = TRUE;
[4837]788
[6711]789 /* Used to count the number of tokens in the "strRealString".
790 */
791 LPSTR strToken = NULL;
792 int nTokens = 0;
793 LPSTR pChar = NULL;
[9400]794
[6711]795 /* Check if we have a valid argument
796 */
797 if( strRealString == NULL )
798 {
799 bValidRealString = FALSE;
800 }
[4837]801
[6711]802 if( bValidRealString == TRUE )
803 {
804 /* Make sure we only have ONE token in the string.
805 */
806 strToken = strtok( strRealString, " " );
[9400]807 while( strToken != NULL ) {
808 nTokens++;
809 strToken = strtok( NULL, " " );
[6711]810 }
[4837]811
[6711]812 if( nTokens != 1 )
813 {
814 bValidRealString = FALSE;
815 }
816 }
[4837]817
818
[6711]819 /* Make sure this token contains only valid characters.
820 * The string argument to atof has the following form:
821 * [whitespace] [sign] [digits] [.digits] [ {d | D | e | E }[sign]digits]
822 * Whitespace consists of space and|or <TAB> characters, which are ignored.
[4837]823 * Sign is either plus '+' or minus '-'.
824 * Digits are one or more decimal digits.
825 * Note: If no digits appear before the decimal point, at least one must
826 * appear after the decimal point.
827 * The decimal digits may be followed by an exponent.
828 * An Exponent consists of an introductory letter ( D, d, E, or e) and
[6711]829 * an optionally signed decimal integer.
830 */
831 pChar = strRealString;
832 while( bValidRealString == TRUE && *pChar != '\0' )
833 {
834 switch( *pChar )
835 {
836 /* If whitespace...
837 */
838 case ' ':
839 case '\t':
840 if( bWhiteSpaceProcessed ||
841 bFirstSignProcessed ||
842 bFirstDigitsProcessed ||
843 bDecimalPointProcessed ||
844 bSecondDigitsProcessed ||
845 bExponentProcessed ||
846 bSecondSignProcessed ||
847 bThirdDigitsProcessed )
848 {
849 bValidRealString = FALSE;
850 }
851 break;
852 /* If sign...
853 */
854 case '+':
855 case '-':
856 if( bFirstSignProcessed == FALSE )
857 {
858 if( bFirstDigitsProcessed ||
859 bDecimalPointProcessed ||
860 bSecondDigitsProcessed ||
861 bExponentProcessed ||
862 bSecondSignProcessed ||
863 bThirdDigitsProcessed )
864 {
865 bValidRealString = FALSE;
866 }
867 bWhiteSpaceProcessed = TRUE;
868 bFirstSignProcessed = TRUE;
869 }
870 else if( bSecondSignProcessed == FALSE )
871 {
[4837]872 /* Note: The exponent must be present in
[6711]873 * order to accept the second sign...
874 */
875 if( bExponentProcessed == FALSE ||
876 bThirdDigitsProcessed ||
877 bDigitsRequired )
878 {
879 bValidRealString = FALSE;
880 }
881 bFirstSignProcessed = TRUE;
882 bWhiteSpaceProcessed = TRUE;
883 bFirstDigitsProcessed = TRUE;
884 bDecimalPointProcessed = TRUE;
885 bSecondDigitsProcessed = TRUE;
886 bSecondSignProcessed = TRUE;
887 }
888 break;
[4837]889
[6711]890 /* If decimals...
891 */
892 case '0':
893 case '1':
894 case '2':
895 case '3':
896 case '4':
897 case '5':
898 case '6':
899 case '7':
900 case '8':
[9400]901 case '9':
[6711]902 if( bFirstDigitsProcessed == FALSE )
903 {
904 if( bDecimalPointProcessed ||
905 bSecondDigitsProcessed ||
906 bExponentProcessed ||
907 bSecondSignProcessed ||
908 bThirdDigitsProcessed )
909 {
910 bValidRealString = FALSE;
911 }
912 bFirstSignProcessed = TRUE;
913 bWhiteSpaceProcessed = TRUE;
914 /* We have found some digits before the decimal point
915 * so disable the "Digits required" flag.
916 */
917 bDigitsRequired = FALSE;
918 }
919 else if( bSecondDigitsProcessed == FALSE )
920 {
921 if( bExponentProcessed ||
922 bSecondSignProcessed ||
923 bThirdDigitsProcessed )
924 {
925 bValidRealString = FALSE;
926 }
927 bFirstSignProcessed = TRUE;
928 bWhiteSpaceProcessed = TRUE;
929 bFirstDigitsProcessed = TRUE;
930 bDecimalPointProcessed = TRUE;
931 /* We have found some digits after the decimal point
932 * so disable the "Digits required" flag.
933 */
934 bDigitsRequired = FALSE;
935 }
936 else if( bThirdDigitsProcessed == FALSE )
937 {
938 /* Getting here means everything else should be processed.
[4837]939 * If we get anything else than a decimal following this
940 * digit it will be flagged by the other cases, so
[6711]941 * we do not really need to do anything in here.
942 */
943 }
944 break;
945 /* If DecimalPoint...
946 */
[9400]947 case '.':
[6711]948 if( bDecimalPointProcessed ||
949 bSecondDigitsProcessed ||
950 bExponentProcessed ||
951 bSecondSignProcessed ||
952 bThirdDigitsProcessed )
953 {
954 bValidRealString = FALSE;
955 }
956 bFirstSignProcessed = TRUE;
957 bWhiteSpaceProcessed = TRUE;
958 bFirstDigitsProcessed = TRUE;
959 bDecimalPointProcessed = TRUE;
960 break;
961 /* If Exponent...
962 */
963 case 'e':
964 case 'E':
965 case 'd':
966 case 'D':
967 if( bExponentProcessed ||
968 bSecondSignProcessed ||
969 bThirdDigitsProcessed ||
970 bDigitsRequired )
971 {
972 bValidRealString = FALSE;
973 }
974 bFirstSignProcessed = TRUE;
975 bWhiteSpaceProcessed = TRUE;
976 bFirstDigitsProcessed = TRUE;
977 bDecimalPointProcessed = TRUE;
978 bSecondDigitsProcessed = TRUE;
979 bExponentProcessed = TRUE;
980 break;
981 default:
982 bValidRealString = FALSE;
983 break;
984 }
985 /* Process next character.
986 */
987 pChar++;
988 }
[4837]989
[6711]990 /* If the required digits were not present we have an invalid
991 * string representation of a real number.
992 */
993 if( bDigitsRequired == TRUE )
994 {
995 bValidRealString = FALSE;
996 }
[4837]997
[6711]998 return bValidRealString;
[4837]999}
1000
1001
1002/******************************************************************************
[6711]1003 * Coerce [INTERNAL]
[4837]1004 *
1005 * This function dispatches execution to the proper conversion API
1006 * to do the necessary coercion.
[6575]1007 *
1008 * FIXME: Passing down dwFlags to the conversion functions is wrong, this
[6711]1009 * is a different flagmask. Check MSDN.
[4837]1010 */
1011static HRESULT Coerce( VARIANTARG* pd, LCID lcid, ULONG dwFlags, VARIANTARG* ps, VARTYPE vt )
1012{
[6711]1013 HRESULT res = S_OK;
1014 unsigned short vtFrom = 0;
1015 vtFrom = V_VT(ps) & VT_TYPEMASK;
[6575]1016
[9400]1017
[6711]1018 /* Note: Since "long" and "int" values both have 4 bytes and are
1019 * both signed integers "int" will be treated as "long" in the
1020 * following code.
1021 * The same goes for their unsigned versions.
1022 */
[4837]1023
[9400]1024 /* Trivial Case: If the coercion is from two types that are
[6711]1025 * identical then we can blindly copy from one argument to another.*/
1026 if ((vt==vtFrom))
1027 {
1028 return VariantCopy(pd,ps);
1029 }
[4837]1030
[6711]1031 /* Cases requiring thought*/
1032 switch( vt )
1033 {
[4837]1034
1035 case( VT_EMPTY ):
1036 res = VariantClear( pd );
1037 break;
1038 case( VT_NULL ):
1039 res = VariantClear( pd );
1040 if( res == S_OK )
1041 {
[6575]1042 V_VT(pd) = VT_NULL;
[4837]1043 }
1044 break;
[6711]1045 case( VT_I1 ):
1046 switch( vtFrom )
[4837]1047 {
1048 case( VT_I1 ):
1049 res = VariantCopy( pd, ps );
1050 break;
[6711]1051 case( VT_I2 ):
1052 res = VarI1FromI2( V_UNION(ps,iVal), &V_UNION(pd,cVal) );
1053 break;
1054 case( VT_INT ):
1055 case( VT_I4 ):
1056 res = VarI1FromI4( V_UNION(ps,lVal), &V_UNION(pd,cVal) );
1057 break;
1058 case( VT_UI1 ):
1059 res = VarI1FromUI1( V_UNION(ps,bVal), &V_UNION(pd,cVal) );
1060 break;
1061 case( VT_UI2 ):
1062 res = VarI1FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,cVal) );
1063 break;
1064 case( VT_UINT ):
1065 case( VT_UI4 ):
1066 res = VarI1FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,cVal) );
1067 break;
1068 case( VT_R4 ):
1069 res = VarI1FromR4( V_UNION(ps,fltVal), &V_UNION(pd,cVal) );
1070 break;
1071 case( VT_R8 ):
1072 res = VarI1FromR8( V_UNION(ps,dblVal), &V_UNION(pd,cVal) );
1073 break;
1074 case( VT_DATE ):
1075 res = VarI1FromDate( V_UNION(ps,date), &V_UNION(pd,cVal) );
1076 break;
1077 case( VT_BOOL ):
1078 res = VarI1FromBool( V_UNION(ps,boolVal), &V_UNION(pd,cVal) );
1079 break;
1080 case( VT_BSTR ):
1081 res = VarI1FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,cVal) );
1082 break;
1083 case( VT_CY ):
1084 res = VarI1FromCy( V_UNION(ps,cyVal), &V_UNION(pd,cVal) );
1085 break;
1086 case( VT_DISPATCH ):
1087 /*res = VarI1FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,cVal) );*/
1088 case( VT_DECIMAL ):
1089 /*res = VarI1FromDec( V_UNION(ps,decVal), &V_UNION(pd,cVal) );*/
1090 case( VT_UNKNOWN ):
1091 default:
1092 res = DISP_E_TYPEMISMATCH;
1093 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1094 break;
1095 }
1096 break;
[4837]1097
[6711]1098 case( VT_I2 ):
1099 switch( vtFrom )
1100 {
1101 case( VT_I1 ):
1102 res = VarI2FromI1( V_UNION(ps,cVal), &V_UNION(pd,iVal) );
1103 break;
[4837]1104 case( VT_I2 ):
1105 res = VariantCopy( pd, ps );
1106 break;
[6711]1107 case( VT_INT ):
1108 case( VT_I4 ):
1109 res = VarI2FromI4( V_UNION(ps,lVal), &V_UNION(pd,iVal) );
1110 break;
1111 case( VT_UI1 ):
1112 res = VarI2FromUI1( V_UNION(ps,bVal), &V_UNION(pd,iVal) );
1113 break;
1114 case( VT_UI2 ):
1115 res = VarI2FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,iVal) );
1116 break;
1117 case( VT_UINT ):
1118 case( VT_UI4 ):
1119 res = VarI2FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,iVal) );
1120 break;
1121 case( VT_R4 ):
1122 res = VarI2FromR4( V_UNION(ps,fltVal), &V_UNION(pd,iVal) );
1123 break;
1124 case( VT_R8 ):
1125 res = VarI2FromR8( V_UNION(ps,dblVal), &V_UNION(pd,iVal) );
1126 break;
1127 case( VT_DATE ):
1128 res = VarI2FromDate( V_UNION(ps,date), &V_UNION(pd,iVal) );
1129 break;
1130 case( VT_BOOL ):
1131 res = VarI2FromBool( V_UNION(ps,boolVal), &V_UNION(pd,iVal) );
1132 break;
1133 case( VT_BSTR ):
1134 res = VarI2FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,iVal) );
1135 break;
1136 case( VT_CY ):
1137 res = VarI2FromCy( V_UNION(ps,cyVal), &V_UNION(pd,iVal) );
1138 break;
1139 case( VT_DISPATCH ):
1140 /*res = VarI2FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,iVal) );*/
1141 case( VT_DECIMAL ):
1142 /*res = VarI2FromDec( V_UNION(ps,deiVal), &V_UNION(pd,iVal) );*/
1143 case( VT_UNKNOWN ):
1144 default:
1145 res = DISP_E_TYPEMISMATCH;
1146 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1147 break;
1148 }
1149 break;
[4837]1150
[6711]1151 case( VT_INT ):
1152 case( VT_I4 ):
1153 switch( vtFrom )
1154 {
[7916]1155 case( VT_EMPTY ):
1156 V_UNION(pd,lVal) = 0;
1157 res = S_OK;
1158 break;
[6711]1159 case( VT_I1 ):
1160 res = VarI4FromI1( V_UNION(ps,cVal), &V_UNION(pd,lVal) );
1161 break;
1162 case( VT_I2 ):
1163 res = VarI4FromI2( V_UNION(ps,iVal), &V_UNION(pd,lVal) );
[4837]1164 break;
1165 case( VT_INT ):
1166 case( VT_I4 ):
[5840]1167#ifdef __WIN32OS2__
1168 case( VT_HRESULT ):
1169#endif
[4837]1170 res = VariantCopy( pd, ps );
1171 break;
[6711]1172 case( VT_UI1 ):
1173 res = VarI4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,lVal) );
1174 break;
1175 case( VT_UI2 ):
1176 res = VarI4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,lVal) );
1177 break;
1178 case( VT_UINT ):
1179 case( VT_UI4 ):
1180 res = VarI4FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,lVal) );
1181 break;
1182 case( VT_R4 ):
1183 res = VarI4FromR4( V_UNION(ps,fltVal), &V_UNION(pd,lVal) );
1184 break;
1185 case( VT_R8 ):
1186 res = VarI4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,lVal) );
1187 break;
1188 case( VT_DATE ):
1189 res = VarI4FromDate( V_UNION(ps,date), &V_UNION(pd,lVal) );
1190 break;
1191 case( VT_BOOL ):
1192 res = VarI4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,lVal) );
1193 break;
1194 case( VT_BSTR ):
1195 res = VarI4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,lVal) );
1196 break;
1197 case( VT_CY ):
1198 res = VarI4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,lVal) );
1199 break;
1200 case( VT_DISPATCH ):
1201 /*res = VarI4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,lVal) );*/
1202 case( VT_DECIMAL ):
1203 /*res = VarI4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,lVal) );*/
1204 case( VT_UNKNOWN ):
1205 default:
1206 res = DISP_E_TYPEMISMATCH;
1207 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1208 break;
1209 }
1210 break;
[4837]1211
[6711]1212 case( VT_UI1 ):
1213 switch( vtFrom )
1214 {
1215 case( VT_I1 ):
1216 res = VarUI1FromI1( V_UNION(ps,cVal), &V_UNION(pd,bVal) );
1217 break;
1218 case( VT_I2 ):
1219 res = VarUI1FromI2( V_UNION(ps,iVal), &V_UNION(pd,bVal) );
1220 break;
1221 case( VT_INT ):
1222 case( VT_I4 ):
1223 res = VarUI1FromI4( V_UNION(ps,lVal), &V_UNION(pd,bVal) );
1224 break;
[4837]1225 case( VT_UI1 ):
1226 res = VariantCopy( pd, ps );
1227 break;
[6711]1228 case( VT_UI2 ):
1229 res = VarUI1FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,bVal) );
1230 break;
1231 case( VT_UINT ):
1232 case( VT_UI4 ):
1233 res = VarUI1FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,bVal) );
1234 break;
1235 case( VT_R4 ):
1236 res = VarUI1FromR4( V_UNION(ps,fltVal), &V_UNION(pd,bVal) );
1237 break;
1238 case( VT_R8 ):
1239 res = VarUI1FromR8( V_UNION(ps,dblVal), &V_UNION(pd,bVal) );
1240 break;
1241 case( VT_DATE ):
1242 res = VarUI1FromDate( V_UNION(ps,date), &V_UNION(pd,bVal) );
1243 break;
1244 case( VT_BOOL ):
1245 res = VarUI1FromBool( V_UNION(ps,boolVal), &V_UNION(pd,bVal) );
1246 break;
1247 case( VT_BSTR ):
1248 res = VarUI1FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,bVal) );
1249 break;
1250 case( VT_CY ):
1251 res = VarUI1FromCy( V_UNION(ps,cyVal), &V_UNION(pd,bVal) );
1252 break;
1253 case( VT_DISPATCH ):
1254 /*res = VarUI1FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,bVal) );*/
1255 case( VT_DECIMAL ):
1256 /*res = VarUI1FromDec( V_UNION(ps,deiVal), &V_UNION(pd,bVal) );*/
1257 case( VT_UNKNOWN ):
1258 default:
1259 res = DISP_E_TYPEMISMATCH;
1260 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1261 break;
1262 }
1263 break;
[4837]1264
[6711]1265 case( VT_UI2 ):
1266 switch( vtFrom )
1267 {
1268 case( VT_I1 ):
1269 res = VarUI2FromI1( V_UNION(ps,cVal), &V_UNION(pd,uiVal) );
1270 break;
1271 case( VT_I2 ):
1272 res = VarUI2FromI2( V_UNION(ps,iVal), &V_UNION(pd,uiVal) );
1273 break;
1274 case( VT_INT ):
1275 case( VT_I4 ):
1276 res = VarUI2FromI4( V_UNION(ps,lVal), &V_UNION(pd,uiVal) );
1277 break;
1278 case( VT_UI1 ):
1279 res = VarUI2FromUI1( V_UNION(ps,bVal), &V_UNION(pd,uiVal) );
1280 break;
[4837]1281 case( VT_UI2 ):
1282 res = VariantCopy( pd, ps );
1283 break;
[6711]1284 case( VT_UINT ):
1285 case( VT_UI4 ):
1286 res = VarUI2FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,uiVal) );
1287 break;
1288 case( VT_R4 ):
1289 res = VarUI2FromR4( V_UNION(ps,fltVal), &V_UNION(pd,uiVal) );
1290 break;
1291 case( VT_R8 ):
1292 res = VarUI2FromR8( V_UNION(ps,dblVal), &V_UNION(pd,uiVal) );
1293 break;
1294 case( VT_DATE ):
1295 res = VarUI2FromDate( V_UNION(ps,date), &V_UNION(pd,uiVal) );
1296 break;
1297 case( VT_BOOL ):
1298 res = VarUI2FromBool( V_UNION(ps,boolVal), &V_UNION(pd,uiVal) );
1299 break;
1300 case( VT_BSTR ):
1301 res = VarUI2FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,uiVal) );
1302 break;
1303 case( VT_CY ):
1304 res = VarUI2FromCy( V_UNION(ps,cyVal), &V_UNION(pd,uiVal) );
1305 break;
1306 case( VT_DISPATCH ):
1307 /*res = VarUI2FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,uiVal) );*/
1308 case( VT_DECIMAL ):
1309 /*res = VarUI2FromDec( V_UNION(ps,deiVal), &V_UNION(pd,uiVal) );*/
1310 case( VT_UNKNOWN ):
1311 default:
1312 res = DISP_E_TYPEMISMATCH;
1313 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1314 break;
1315 }
1316 break;
[4837]1317
[6711]1318 case( VT_UINT ):
1319 case( VT_UI4 ):
1320 switch( vtFrom )
1321 {
1322 case( VT_I1 ):
1323 res = VarUI4FromI1( V_UNION(ps,cVal), &V_UNION(pd,ulVal) );
1324 break;
1325 case( VT_I2 ):
1326 res = VarUI4FromI2( V_UNION(ps,iVal), &V_UNION(pd,ulVal) );
1327 break;
1328 case( VT_INT ):
1329 case( VT_I4 ):
1330 res = VarUI4FromI4( V_UNION(ps,lVal), &V_UNION(pd,ulVal) );
1331 break;
1332 case( VT_UI1 ):
1333 res = VarUI4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,ulVal) );
1334 break;
1335 case( VT_UI2 ):
1336 res = VarUI4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,ulVal) );
1337 break;
[4837]1338 case( VT_UI4 ):
1339 res = VariantCopy( pd, ps );
1340 break;
[6711]1341 case( VT_R4 ):
1342 res = VarUI4FromR4( V_UNION(ps,fltVal), &V_UNION(pd,ulVal) );
1343 break;
1344 case( VT_R8 ):
1345 res = VarUI4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,ulVal) );
1346 break;
1347 case( VT_DATE ):
1348 res = VarUI4FromDate( V_UNION(ps,date), &V_UNION(pd,ulVal) );
1349 break;
1350 case( VT_BOOL ):
1351 res = VarUI4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,ulVal) );
1352 break;
1353 case( VT_BSTR ):
1354 res = VarUI4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,ulVal) );
1355 break;
1356 case( VT_CY ):
1357 res = VarUI4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,ulVal) );
1358 break;
1359 case( VT_DISPATCH ):
1360 /*res = VarUI4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,ulVal) );*/
1361 case( VT_DECIMAL ):
1362 /*res = VarUI4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,ulVal) );*/
1363 case( VT_UNKNOWN ):
1364 default:
1365 res = DISP_E_TYPEMISMATCH;
1366 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1367 break;
1368 }
1369 break;
[9400]1370
[6711]1371 case( VT_R4 ):
1372 switch( vtFrom )
1373 {
1374 case( VT_I1 ):
1375 res = VarR4FromI1( V_UNION(ps,cVal), &V_UNION(pd,fltVal) );
1376 break;
1377 case( VT_I2 ):
1378 res = VarR4FromI2( V_UNION(ps,iVal), &V_UNION(pd,fltVal) );
1379 break;
1380 case( VT_INT ):
1381 case( VT_I4 ):
1382 res = VarR4FromI4( V_UNION(ps,lVal), &V_UNION(pd,fltVal) );
1383 break;
1384 case( VT_UI1 ):
1385 res = VarR4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,fltVal) );
1386 break;
1387 case( VT_UI2 ):
1388 res = VarR4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,fltVal) );
1389 break;
1390 case( VT_UINT ):
1391 case( VT_UI4 ):
1392 res = VarR4FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,fltVal) );
1393 break;
[4837]1394 case( VT_R4 ):
1395 res = VariantCopy( pd, ps );
1396 break;
[6711]1397 case( VT_R8 ):
1398 res = VarR4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,fltVal) );
1399 break;
1400 case( VT_DATE ):
1401 res = VarR4FromDate( V_UNION(ps,date), &V_UNION(pd,fltVal) );
1402 break;
1403 case( VT_BOOL ):
1404 res = VarR4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,fltVal) );
1405 break;
1406 case( VT_BSTR ):
1407 res = VarR4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,fltVal) );
1408 break;
1409 case( VT_CY ):
1410 res = VarR4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,fltVal) );
1411 break;
1412 case( VT_DISPATCH ):
1413 /*res = VarR4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,fltVal) );*/
1414 case( VT_DECIMAL ):
1415 /*res = VarR4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,fltVal) );*/
1416 case( VT_UNKNOWN ):
1417 default:
1418 res = DISP_E_TYPEMISMATCH;
1419 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1420 break;
1421 }
1422 break;
[4837]1423
[6711]1424 case( VT_R8 ):
1425 switch( vtFrom )
1426 {
1427 case( VT_I1 ):
1428 res = VarR8FromI1( V_UNION(ps,cVal), &V_UNION(pd,dblVal) );
1429 break;
1430 case( VT_I2 ):
1431 res = VarR8FromI2( V_UNION(ps,iVal), &V_UNION(pd,dblVal) );
1432 break;
1433 case( VT_INT ):
1434 case( VT_I4 ):
1435 res = VarR8FromI4( V_UNION(ps,lVal), &V_UNION(pd,dblVal) );
1436 break;
1437 case( VT_UI1 ):
1438 res = VarR8FromUI1( V_UNION(ps,bVal), &V_UNION(pd,dblVal) );
1439 break;
1440 case( VT_UI2 ):
1441 res = VarR8FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,dblVal) );
1442 break;
1443 case( VT_UINT ):
1444 case( VT_UI4 ):
1445 res = VarR8FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,dblVal) );
1446 break;
1447 case( VT_R4 ):
1448 res = VarR8FromR4( V_UNION(ps,fltVal), &V_UNION(pd,dblVal) );
1449 break;
[4837]1450 case( VT_R8 ):
1451 res = VariantCopy( pd, ps );
1452 break;
[6711]1453 case( VT_DATE ):
1454 res = VarR8FromDate( V_UNION(ps,date), &V_UNION(pd,dblVal) );
1455 break;
1456 case( VT_BOOL ):
1457 res = VarR8FromBool( V_UNION(ps,boolVal), &V_UNION(pd,dblVal) );
1458 break;
1459 case( VT_BSTR ):
1460 res = VarR8FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,dblVal) );
1461 break;
1462 case( VT_CY ):
1463 res = VarR8FromCy( V_UNION(ps,cyVal), &V_UNION(pd,dblVal) );
1464 break;
1465 case( VT_DISPATCH ):
1466 /*res = VarR8FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,dblVal) );*/
1467 case( VT_DECIMAL ):
1468 /*res = VarR8FromDec( V_UNION(ps,deiVal), &V_UNION(pd,dblVal) );*/
1469 case( VT_UNKNOWN ):
1470 default:
1471 res = DISP_E_TYPEMISMATCH;
1472 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1473 break;
1474 }
1475 break;
[4837]1476
[6711]1477 case( VT_DATE ):
1478 switch( vtFrom )
1479 {
1480 case( VT_I1 ):
1481 res = VarDateFromI1( V_UNION(ps,cVal), &V_UNION(pd,date) );
1482 break;
1483 case( VT_I2 ):
1484 res = VarDateFromI2( V_UNION(ps,iVal), &V_UNION(pd,date) );
1485 break;
1486 case( VT_INT ):
1487 res = VarDateFromInt( V_UNION(ps,intVal), &V_UNION(pd,date) );
1488 break;
1489 case( VT_I4 ):
1490 res = VarDateFromI4( V_UNION(ps,lVal), &V_UNION(pd,date) );
1491 break;
1492 case( VT_UI1 ):
1493 res = VarDateFromUI1( V_UNION(ps,bVal), &V_UNION(pd,date) );
1494 break;
1495 case( VT_UI2 ):
1496 res = VarDateFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,date) );
1497 break;
1498 case( VT_UINT ):
1499 res = VarDateFromUint( V_UNION(ps,uintVal), &V_UNION(pd,date) );
1500 break;
1501 case( VT_UI4 ):
1502 res = VarDateFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,date) );
1503 break;
1504 case( VT_R4 ):
1505 res = VarDateFromR4( V_UNION(ps,fltVal), &V_UNION(pd,date) );
1506 break;
1507 case( VT_R8 ):
1508 res = VarDateFromR8( V_UNION(ps,dblVal), &V_UNION(pd,date) );
1509 break;
[4837]1510 case( VT_DATE ):
1511 res = VariantCopy( pd, ps );
1512 break;
[6711]1513 case( VT_BOOL ):
1514 res = VarDateFromBool( V_UNION(ps,boolVal), &V_UNION(pd,date) );
1515 break;
1516 case( VT_BSTR ):
1517 res = VarDateFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,date) );
1518 break;
1519 case( VT_CY ):
1520 res = VarDateFromCy( V_UNION(ps,cyVal), &V_UNION(pd,date) );
1521 break;
1522 case( VT_DISPATCH ):
1523 /*res = VarDateFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,date) );*/
1524 case( VT_DECIMAL ):
1525 /*res = VarDateFromDec( V_UNION(ps,deiVal), &V_UNION(pd,date) );*/
1526 case( VT_UNKNOWN ):
1527 default:
1528 res = DISP_E_TYPEMISMATCH;
1529 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1530 break;
1531 }
1532 break;
[4837]1533
[6711]1534 case( VT_BOOL ):
1535 switch( vtFrom )
1536 {
[7916]1537 case( VT_EMPTY ):
1538 res = S_OK;
1539 V_UNION(pd,boolVal) = VARIANT_FALSE;
1540 break;
[6711]1541 case( VT_I1 ):
1542 res = VarBoolFromI1( V_UNION(ps,cVal), &V_UNION(pd,boolVal) );
1543 break;
1544 case( VT_I2 ):
1545 res = VarBoolFromI2( V_UNION(ps,iVal), &V_UNION(pd,boolVal) );
1546 break;
1547 case( VT_INT ):
1548 res = VarBoolFromInt( V_UNION(ps,intVal), &V_UNION(pd,boolVal) );
1549 break;
1550 case( VT_I4 ):
1551 res = VarBoolFromI4( V_UNION(ps,lVal), &V_UNION(pd,boolVal) );
1552 break;
1553 case( VT_UI1 ):
1554 res = VarBoolFromUI1( V_UNION(ps,bVal), &V_UNION(pd,boolVal) );
1555 break;
1556 case( VT_UI2 ):
1557 res = VarBoolFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,boolVal) );
1558 break;
1559 case( VT_UINT ):
1560 res = VarBoolFromUint( V_UNION(ps,uintVal), &V_UNION(pd,boolVal) );
1561 break;
1562 case( VT_UI4 ):
1563 res = VarBoolFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,boolVal) );
1564 break;
1565 case( VT_R4 ):
1566 res = VarBoolFromR4( V_UNION(ps,fltVal), &V_UNION(pd,boolVal) );
1567 break;
1568 case( VT_R8 ):
1569 res = VarBoolFromR8( V_UNION(ps,dblVal), &V_UNION(pd,boolVal) );
1570 break;
1571 case( VT_DATE ):
1572 res = VarBoolFromDate( V_UNION(ps,date), &V_UNION(pd,boolVal) );
1573 break;
[4837]1574 case( VT_BOOL ):
1575 res = VariantCopy( pd, ps );
1576 break;
[6711]1577 case( VT_BSTR ):
1578 res = VarBoolFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,boolVal) );
1579 break;
1580 case( VT_CY ):
1581 res = VarBoolFromCy( V_UNION(ps,cyVal), &V_UNION(pd,boolVal) );
1582 break;
1583 case( VT_DISPATCH ):
1584 /*res = VarBoolFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,boolVal) );*/
1585 case( VT_DECIMAL ):
1586 /*res = VarBoolFromDec( V_UNION(ps,deiVal), &V_UNION(pd,boolVal) );*/
1587 case( VT_UNKNOWN ):
1588 default:
1589 res = DISP_E_TYPEMISMATCH;
1590 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1591 break;
1592 }
1593 break;
[4837]1594
[6711]1595 case( VT_BSTR ):
1596 switch( vtFrom )
1597 {
1598 case( VT_EMPTY ):
1599 if ((V_UNION(pd,bstrVal) = SysAllocStringLen(NULL, 0)))
1600 res = S_OK;
1601 else
1602 res = E_OUTOFMEMORY;
1603 break;
1604 case( VT_I1 ):
1605 res = VarBstrFromI1( V_UNION(ps,cVal), lcid, 0, &V_UNION(pd,bstrVal) );
1606 break;
1607 case( VT_I2 ):
1608 res = VarBstrFromI2( V_UNION(ps,iVal), lcid, 0, &V_UNION(pd,bstrVal) );
1609 break;
1610 case( VT_INT ):
1611 res = VarBstrFromInt( V_UNION(ps,intVal), lcid, 0, &V_UNION(pd,bstrVal) );
1612 break;
1613 case( VT_I4 ):
1614 res = VarBstrFromI4( V_UNION(ps,lVal), lcid, 0, &V_UNION(pd,bstrVal) );
1615 break;
1616 case( VT_UI1 ):
1617 res = VarBstrFromUI1( V_UNION(ps,bVal), lcid, 0, &V_UNION(pd,bstrVal) );
1618 break;
1619 case( VT_UI2 ):
1620 res = VarBstrFromUI2( V_UNION(ps,uiVal), lcid, 0, &V_UNION(pd,bstrVal) );
1621 break;
1622 case( VT_UINT ):
1623 res = VarBstrFromUint( V_UNION(ps,uintVal), lcid, 0, &V_UNION(pd,bstrVal) );
1624 break;
1625 case( VT_UI4 ):
1626 res = VarBstrFromUI4( V_UNION(ps,ulVal), lcid, 0, &V_UNION(pd,bstrVal) );
1627 break;
1628 case( VT_R4 ):
1629 res = VarBstrFromR4( V_UNION(ps,fltVal), lcid, 0, &V_UNION(pd,bstrVal) );
1630 break;
1631 case( VT_R8 ):
1632 res = VarBstrFromR8( V_UNION(ps,dblVal), lcid, 0, &V_UNION(pd,bstrVal) );
1633 break;
1634 case( VT_DATE ):
1635 res = VarBstrFromDate( V_UNION(ps,date), lcid, 0, &V_UNION(pd,bstrVal) );
1636 break;
1637 case( VT_BOOL ):
1638 res = VarBstrFromBool( V_UNION(ps,boolVal), lcid, 0, &V_UNION(pd,bstrVal) );
1639 break;
1640 case( VT_BSTR ):
1641 res = VariantCopy( pd, ps );
1642 break;
1643 case( VT_CY ):
1644 res = VarBstrFromCy( V_UNION(ps,cyVal), lcid, 0, &V_UNION(pd,bstrVal) );
1645 break;
1646 case( VT_DISPATCH ):
1647 /*res = VarBstrFromDisp( V_UNION(ps,pdispVal), lcid, 0, &(pd,bstrVal) );*/
1648 case( VT_DECIMAL ):
1649 /*res = VarBstrFromDec( V_UNION(ps,deiVal), lcid, 0, &(pd,bstrVal) );*/
1650 case( VT_UNKNOWN ):
1651 default:
1652 res = DISP_E_TYPEMISMATCH;
1653 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1654 break;
1655 }
1656 break;
[4837]1657
1658 case( VT_CY ):
[6711]1659 switch( vtFrom )
1660 {
1661 case( VT_I1 ):
1662 res = VarCyFromI1( V_UNION(ps,cVal), &V_UNION(pd,cyVal) );
1663 break;
1664 case( VT_I2 ):
1665 res = VarCyFromI2( V_UNION(ps,iVal), &V_UNION(pd,cyVal) );
1666 break;
1667 case( VT_INT ):
1668 res = VarCyFromInt( V_UNION(ps,intVal), &V_UNION(pd,cyVal) );
1669 break;
1670 case( VT_I4 ):
1671 res = VarCyFromI4( V_UNION(ps,lVal), &V_UNION(pd,cyVal) );
1672 break;
1673 case( VT_UI1 ):
1674 res = VarCyFromUI1( V_UNION(ps,bVal), &V_UNION(pd,cyVal) );
1675 break;
1676 case( VT_UI2 ):
1677 res = VarCyFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,cyVal) );
1678 break;
1679 case( VT_UINT ):
1680 res = VarCyFromUint( V_UNION(ps,uintVal), &V_UNION(pd,cyVal) );
1681 break;
1682 case( VT_UI4 ):
1683 res = VarCyFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,cyVal) );
1684 break;
1685 case( VT_R4 ):
1686 res = VarCyFromR4( V_UNION(ps,fltVal), &V_UNION(pd,cyVal) );
1687 break;
1688 case( VT_R8 ):
1689 res = VarCyFromR8( V_UNION(ps,dblVal), &V_UNION(pd,cyVal) );
1690 break;
1691 case( VT_DATE ):
1692 res = VarCyFromDate( V_UNION(ps,date), &V_UNION(pd,cyVal) );
1693 break;
1694 case( VT_BOOL ):
1695 res = VarCyFromBool( V_UNION(ps,date), &V_UNION(pd,cyVal) );
1696 break;
1697 case( VT_CY ):
1698 res = VariantCopy( pd, ps );
1699 break;
1700 case( VT_BSTR ):
1701 res = VarCyFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,cyVal) );
1702 break;
1703 case( VT_DISPATCH ):
1704 /*res = VarCyFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,cyVal) );*/
1705 case( VT_DECIMAL ):
1706 /*res = VarCyFromDec( V_UNION(ps,deiVal), &V_UNION(pd,cyVal) );*/
1707 break;
1708 case( VT_UNKNOWN ):
1709 default:
1710 res = DISP_E_TYPEMISMATCH;
1711 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1712 break;
1713 }
1714 break;
[4837]1715
[6952]1716 case( VT_UNKNOWN ):
1717 if (vtFrom == VT_DISPATCH)
1718 {
1719 res = IDispatch_QueryInterface(V_DISPATCH(ps), &IID_IUnknown, (LPVOID*)&V_UNKNOWN(pd));
1720 }
1721 else
1722 {
1723 res = DISP_E_TYPEMISMATCH;
1724 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1725 }
1726 break;
1727
[6711]1728 default:
1729 res = DISP_E_TYPEMISMATCH;
1730 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1731 break;
1732 }
[9400]1733
[6711]1734 return res;
[4837]1735}
1736
1737/******************************************************************************
[6711]1738 * ValidateVtRange [INTERNAL]
[4837]1739 *
1740 * Used internally by the hi-level Variant API to determine
1741 * if the vartypes are valid.
1742 */
1743static HRESULT WINAPI ValidateVtRange( VARTYPE vt )
1744{
1745 /* if by value we must make sure it is in the
1746 * range of the valid types.
1747 */
1748 if( ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1749 {
1750 return DISP_E_BADVARTYPE;
1751 }
1752 return S_OK;
1753}
1754
1755
1756/******************************************************************************
[6711]1757 * ValidateVartype [INTERNAL]
[4837]1758 *
1759 * Used internally by the hi-level Variant API to determine
1760 * if the vartypes are valid.
1761 */
1762static HRESULT WINAPI ValidateVariantType( VARTYPE vt )
1763{
[6711]1764 HRESULT res = S_OK;
[4837]1765
[6711]1766 /* check if we have a valid argument.
1767 */
1768 if( vt & VT_BYREF )
[4837]1769 {
1770 /* if by reference check that the type is in
1771 * the valid range and that it is not of empty or null type
1772 */
1773 if( ( vt & VT_TYPEMASK ) == VT_EMPTY ||
1774 ( vt & VT_TYPEMASK ) == VT_NULL ||
[6711]1775 ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1776 {
[8450]1777 res = DISP_E_BADVARTYPE;
[6711]1778 }
[9400]1779
[4837]1780 }
1781 else
1782 {
1783 res = ValidateVtRange( vt );
1784 }
[9400]1785
[6711]1786 return res;
[4837]1787}
1788
1789/******************************************************************************
[6711]1790 * ValidateVt [INTERNAL]
[4837]1791 *
1792 * Used internally by the hi-level Variant API to determine
1793 * if the vartypes are valid.
1794 */
1795static HRESULT WINAPI ValidateVt( VARTYPE vt )
1796{
[6711]1797 HRESULT res = S_OK;
[4837]1798
[6711]1799 /* check if we have a valid argument.
1800 */
1801 if( vt & VT_BYREF )
[4837]1802 {
1803 /* if by reference check that the type is in
1804 * the valid range and that it is not of empty or null type
1805 */
1806 if( ( vt & VT_TYPEMASK ) == VT_EMPTY ||
1807 ( vt & VT_TYPEMASK ) == VT_NULL ||
[6711]1808 ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1809 {
1810 res = DISP_E_BADVARTYPE;
1811 }
[9400]1812
[4837]1813 }
1814 else
1815 {
1816 res = ValidateVtRange( vt );
1817 }
[9400]1818
[6711]1819 return res;
[4837]1820}
1821
1822
1823
1824
1825
1826/******************************************************************************
[6711]1827 * VariantInit [OLEAUT32.8]
[4837]1828 *
[6944]1829 * Initializes the Variant. Unlike VariantClear it does not interpret
1830 * the current contents of the Variant.
[4837]1831 */
1832void WINAPI VariantInit(VARIANTARG* pvarg)
1833{
[21308]1834 TRACE("(%p)\n",pvarg);
[4837]1835
1836 memset(pvarg, 0, sizeof (VARIANTARG));
[6575]1837 V_VT(pvarg) = VT_EMPTY;
[4837]1838
1839 return;
1840}
1841
1842/******************************************************************************
[6711]1843 * VariantClear [OLEAUT32.9]
[4837]1844 *
1845 * This function clears the VARIANT by setting the vt field to VT_EMPTY. It also
[6711]1846 * sets the wReservedX field to 0. The current contents of the VARIANT are
[4837]1847 * freed. If the vt is VT_BSTR the string is freed. If VT_DISPATCH the object is
1848 * released. If VT_ARRAY the array is freed.
1849 */
1850HRESULT WINAPI VariantClear(VARIANTARG* pvarg)
1851{
1852 HRESULT res = S_OK;
[21308]1853 TRACE("(%p)\n",pvarg);
[4837]1854
[6575]1855 res = ValidateVariantType( V_VT(pvarg) );
[4837]1856 if( res == S_OK )
1857 {
[6575]1858 if( !( V_VT(pvarg) & VT_BYREF ) )
[4837]1859 {
1860 /*
1861 * The VT_ARRAY flag is a special case of a safe array.
1862 */
[6575]1863 if ( (V_VT(pvarg) & VT_ARRAY) != 0)
[4837]1864 {
[6711]1865 SafeArrayDestroy(V_UNION(pvarg,parray));
[4837]1866 }
1867 else
1868 {
[6711]1869 switch( V_VT(pvarg) & VT_TYPEMASK )
1870 {
1871 case( VT_BSTR ):
1872 SysFreeString( V_UNION(pvarg,bstrVal) );
1873 break;
1874 case( VT_DISPATCH ):
1875 if(V_UNION(pvarg,pdispVal)!=NULL)
1876 ICOM_CALL(Release,V_UNION(pvarg,pdispVal));
1877 break;
1878 case( VT_VARIANT ):
1879 VariantClear(V_UNION(pvarg,pvarVal));
1880 break;
1881 case( VT_UNKNOWN ):
1882 if(V_UNION(pvarg,punkVal)!=NULL)
1883 ICOM_CALL(Release,V_UNION(pvarg,punkVal));
1884 break;
1885 case( VT_SAFEARRAY ):
1886 SafeArrayDestroy(V_UNION(pvarg,parray));
1887 break;
1888 default:
1889 break;
1890 }
[4837]1891 }
1892 }
[9400]1893
[4837]1894 /*
1895 * Empty all the fields and mark the type as empty.
1896 */
1897 memset(pvarg, 0, sizeof (VARIANTARG));
[6575]1898 V_VT(pvarg) = VT_EMPTY;
[4837]1899 }
1900
1901 return res;
1902}
1903
1904/******************************************************************************
[6711]1905 * VariantCopy [OLEAUT32.10]
[4837]1906 *
1907 * Frees up the designation variant and makes a copy of the source.
1908 */
1909HRESULT WINAPI VariantCopy(VARIANTARG* pvargDest, VARIANTARG* pvargSrc)
1910{
1911 HRESULT res = S_OK;
1912
[21308]1913 TRACE("(%p, %p), vt=%d\n", pvargDest, pvargSrc, V_VT(pvargSrc));
[4837]1914
[6575]1915 res = ValidateVariantType( V_VT(pvargSrc) );
[4837]1916
1917 /* If the pointer are to the same variant we don't need
1918 * to do anything.
1919 */
1920 if( pvargDest != pvargSrc && res == S_OK )
1921 {
1922 res = VariantClear( pvargDest );
[9400]1923
[4837]1924 if( res == S_OK )
1925 {
[6575]1926 if( V_VT(pvargSrc) & VT_BYREF )
[4837]1927 {
[6711]1928 /* In the case of byreference we only need
1929 * to copy the pointer.
1930 */
1931 pvargDest->n1.n2.n3 = pvargSrc->n1.n2.n3;
1932 V_VT(pvargDest) = V_VT(pvargSrc);
[4837]1933 }
1934 else
1935 {
[6711]1936 /*
1937 * The VT_ARRAY flag is another way to designate a safe array.
1938 */
1939 if (V_VT(pvargSrc) & VT_ARRAY)
1940 {
1941 SafeArrayCopy(V_UNION(pvargSrc,parray), &V_UNION(pvargDest,parray));
1942 }
1943 else
1944 {
1945 /* In the case of by value we need to
[6944]1946 * copy the actual value. In the case of
[6711]1947 * VT_BSTR a copy of the string is made,
[6944]1948 * if VT_DISPATCH or VT_IUNKNOWN AddRef is
[6711]1949 * called to increment the object's reference count.
1950 */
1951 switch( V_VT(pvargSrc) & VT_TYPEMASK )
1952 {
1953 case( VT_BSTR ):
[6944]1954 V_UNION(pvargDest,bstrVal) = SYSDUPSTRING( V_UNION(pvargSrc,bstrVal) );
[6711]1955 break;
1956 case( VT_DISPATCH ):
1957 V_UNION(pvargDest,pdispVal) = V_UNION(pvargSrc,pdispVal);
1958 if (V_UNION(pvargDest,pdispVal)!=NULL)
1959 ICOM_CALL(AddRef,V_UNION(pvargDest,pdispVal));
1960 break;
1961 case( VT_VARIANT ):
1962 VariantCopy(V_UNION(pvargDest,pvarVal),V_UNION(pvargSrc,pvarVal));
1963 break;
1964 case( VT_UNKNOWN ):
1965 V_UNION(pvargDest,punkVal) = V_UNION(pvargSrc,punkVal);
1966 if (V_UNION(pvargDest,pdispVal)!=NULL)
1967 ICOM_CALL(AddRef,V_UNION(pvargDest,punkVal));
1968 break;
1969 case( VT_SAFEARRAY ):
1970 SafeArrayCopy(V_UNION(pvargSrc,parray), &V_UNION(pvargDest,parray));
1971 break;
1972 default:
1973 pvargDest->n1.n2.n3 = pvargSrc->n1.n2.n3;
1974 break;
1975 }
1976 }
[9400]1977
[6711]1978 V_VT(pvargDest) = V_VT(pvargSrc);
[9400]1979 }
[4837]1980 }
1981 }
1982
1983 return res;
1984}
1985
1986
1987/******************************************************************************
[6711]1988 * VariantCopyInd [OLEAUT32.11]
[4837]1989 *
1990 * Frees up the destination variant and makes a copy of the source. If
1991 * the source is of type VT_BYREF it performs the necessary indirections.
1992 */
1993HRESULT WINAPI VariantCopyInd(VARIANT* pvargDest, VARIANTARG* pvargSrc)
1994{
1995 HRESULT res = S_OK;
1996
1997 TRACE("(%p, %p)\n", pvargDest, pvargSrc);
1998
[6575]1999 res = ValidateVariantType( V_VT(pvargSrc) );
[4837]2000
2001 if( res != S_OK )
2002 return res;
[9400]2003
[6575]2004 if( V_VT(pvargSrc) & VT_BYREF )
[4837]2005 {
2006 VARIANTARG varg;
2007 VariantInit( &varg );
2008
2009 /* handle the in place copy.
2010 */
2011 if( pvargDest == pvargSrc )
2012 {
2013 /* we will use a copy of the source instead.
2014 */
2015 res = VariantCopy( &varg, pvargSrc );
2016 pvargSrc = &varg;
2017 }
2018
2019 if( res == S_OK )
2020 {
2021 res = VariantClear( pvargDest );
2022
2023 if( res == S_OK )
2024 {
[6711]2025 /*
2026 * The VT_ARRAY flag is another way to designate a safearray variant.
2027 */
2028 if ( V_VT(pvargSrc) & VT_ARRAY)
2029 {
2030 SafeArrayCopy(*V_UNION(pvargSrc,pparray), &V_UNION(pvargDest,parray));
2031 }
2032 else
2033 {
2034 /* In the case of by reference we need
2035 * to copy the date pointed to by the variant.
2036 */
[4837]2037
[6711]2038 /* Get the variant type.
2039 */
2040 switch( V_VT(pvargSrc) & VT_TYPEMASK )
2041 {
2042 case( VT_BSTR ):
[6944]2043 V_UNION(pvargDest,bstrVal) = SYSDUPSTRING( *(V_UNION(pvargSrc,pbstrVal)) );
[6711]2044 break;
2045 case( VT_DISPATCH ):
2046 break;
2047 case( VT_VARIANT ):
2048 {
2049 /* Prevent from cycling. According to tests on
2050 * VariantCopyInd in Windows and the documentation
2051 * this API dereferences the inner Variants to only one depth.
2052 * If the inner Variant itself contains an
2053 * other inner variant the E_INVALIDARG error is
[9400]2054 * returned.
[6711]2055 */
2056 if( pvargSrc->n1.n2.wReserved1 & PROCESSING_INNER_VARIANT )
2057 {
2058 /* If we get here we are attempting to deference
2059 * an inner variant that that is itself contained
2060 * in an inner variant so report E_INVALIDARG error.
2061 */
2062 res = E_INVALIDARG;
2063 }
2064 else
2065 {
2066 /* Set the processing inner variant flag.
2067 * We will set this flag in the inner variant
2068 * that will be passed to the VariantCopyInd function.
2069 */
2070 (V_UNION(pvargSrc,pvarVal))->n1.n2.wReserved1 |= PROCESSING_INNER_VARIANT;
[9400]2071
[6711]2072 /* Dereference the inner variant.
2073 */
2074 res = VariantCopyInd( pvargDest, V_UNION(pvargSrc,pvarVal) );
2075 /* We must also copy its type, I think.
2076 */
2077 V_VT(pvargSrc) = V_VT(V_UNION(pvargSrc,pvarVal));
2078 }
2079 }
2080 break;
2081 case( VT_UNKNOWN ):
2082 break;
2083 case( VT_SAFEARRAY ):
2084 SafeArrayCopy(*V_UNION(pvargSrc,pparray), &V_UNION(pvargDest,parray));
2085 break;
2086 default:
2087 /* This is a by reference Variant which means that the union
2088 * part of the Variant contains a pointer to some data of
2089 * type "V_VT(pvargSrc) & VT_TYPEMASK".
2090 * We will deference this data in a generic fashion using
2091 * the void pointer "Variant.u.byref".
2092 * We will copy this data into the union of the destination
2093 * Variant.
2094 */
[7916]2095 memcpy( &pvargDest->n1.n2.n3, V_UNION(pvargSrc,byref), SizeOfVariantData( pvargSrc ) );
[6711]2096 break;
2097 }
2098 }
[8450]2099
2100 if (res == S_OK) V_VT(pvargDest) = V_VT(pvargSrc) & VT_TYPEMASK;
[4837]2101 }
2102 }
2103
2104 /* this should not fail.
2105 */
2106 VariantClear( &varg );
2107 }
2108 else
2109 {
2110 res = VariantCopy( pvargDest, pvargSrc );
2111 }
2112
2113 return res;
2114}
2115
2116/******************************************************************************
[6711]2117 * VariantChangeType [OLEAUT32.12]
[4837]2118 */
2119HRESULT WINAPI VariantChangeType(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
[6711]2120 USHORT wFlags, VARTYPE vt)
[4837]2121{
[6711]2122 return VariantChangeTypeEx( pvargDest, pvargSrc, 0, wFlags, vt );
[4837]2123}
2124
2125/******************************************************************************
[6711]2126 * VariantChangeTypeEx [OLEAUT32.147]
[4837]2127 */
2128HRESULT WINAPI VariantChangeTypeEx(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
[6711]2129 LCID lcid, USHORT wFlags, VARTYPE vt)
[4837]2130{
[6711]2131 HRESULT res = S_OK;
2132 VARIANTARG varg;
2133 VariantInit( &varg );
[21308]2134
2135 TRACE("(%p, %p, %ld, %u, %u) vt=%d\n", pvargDest, pvargSrc, lcid, wFlags, vt, V_VT(pvargSrc));
[9400]2136 TRACE("Src Var:\n");
2137 dump_Variant(pvargSrc);
[4837]2138
[6711]2139 /* validate our source argument.
2140 */
2141 res = ValidateVariantType( V_VT(pvargSrc) );
[4837]2142
[6711]2143 /* validate the vartype.
2144 */
2145 if( res == S_OK )
2146 {
2147 res = ValidateVt( vt );
2148 }
[4837]2149
[6711]2150 /* if we are doing an in-place conversion make a copy of the source.
2151 */
2152 if( res == S_OK && pvargDest == pvargSrc )
2153 {
2154 res = VariantCopy( &varg, pvargSrc );
2155 pvargSrc = &varg;
2156 }
[4837]2157
[6711]2158 if( res == S_OK )
2159 {
2160 /* free up the destination variant.
2161 */
2162 res = VariantClear( pvargDest );
2163 }
[4837]2164
[6711]2165 if( res == S_OK )
2166 {
2167 if( V_VT(pvargSrc) & VT_BYREF )
2168 {
2169 /* Convert the source variant to a "byvalue" variant.
2170 */
2171 VARIANTARG Variant;
2172 VariantInit( &Variant );
2173 res = VariantCopyInd( &Variant, pvargSrc );
2174 if( res == S_OK )
2175 {
2176 res = Coerce( pvargDest, lcid, wFlags, &Variant, vt );
2177 /* this should not fail.
2178 */
2179 VariantClear( &Variant );
2180 }
[21308]2181
[6711]2182 }
2183 else
2184 {
2185 /* Use the current "byvalue" source variant.
2186 */
2187 res = Coerce( pvargDest, lcid, wFlags, pvargSrc, vt );
2188 }
2189 }
2190 /* this should not fail.
2191 */
2192 VariantClear( &varg );
[9400]2193
[6711]2194 /* set the type of the destination
2195 */
2196 if ( res == S_OK )
2197 V_VT(pvargDest) = vt;
[4837]2198
[21308]2199 TRACE("Dest Var:\n");
[9400]2200 dump_Variant(pvargDest);
2201
[6711]2202 return res;
[4837]2203}
2204
2205
2206
2207
2208/******************************************************************************
[6711]2209 * VarUI1FromI2 [OLEAUT32.130]
[4837]2210 */
2211HRESULT WINAPI VarUI1FromI2(short sIn, BYTE* pbOut)
2212{
[6711]2213 TRACE("( %d, %p ), stub\n", sIn, pbOut );
[4837]2214
[6711]2215 /* Check range of value.
2216 */
2217 if( sIn < UI1_MIN || sIn > UI1_MAX )
2218 {
2219 return DISP_E_OVERFLOW;
2220 }
[4837]2221
[6711]2222 *pbOut = (BYTE) sIn;
[9400]2223
[6711]2224 return S_OK;
[4837]2225}
2226
2227/******************************************************************************
[6711]2228 * VarUI1FromI4 [OLEAUT32.131]
[4837]2229 */
2230HRESULT WINAPI VarUI1FromI4(LONG lIn, BYTE* pbOut)
2231{
[6711]2232 TRACE("( %ld, %p ), stub\n", lIn, pbOut );
[4837]2233
[6711]2234 /* Check range of value.
2235 */
2236 if( lIn < UI1_MIN || lIn > UI1_MAX )
2237 {
2238 return DISP_E_OVERFLOW;
2239 }
[4837]2240
[6711]2241 *pbOut = (BYTE) lIn;
[9400]2242
[6711]2243 return S_OK;
[4837]2244}
2245
2246
2247/******************************************************************************
[6711]2248 * VarUI1FromR4 [OLEAUT32.132]
[4837]2249 */
2250HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut)
2251{
[6711]2252 TRACE("( %f, %p ), stub\n", fltIn, pbOut );
[4837]2253
[6711]2254 /* Check range of value.
[4837]2255 */
[21916]2256 fltIn = rnd( fltIn );
[6711]2257 if( fltIn < UI1_MIN || fltIn > UI1_MAX )
2258 {
2259 return DISP_E_OVERFLOW;
2260 }
[4837]2261
[6711]2262 *pbOut = (BYTE) fltIn;
[9400]2263
[6711]2264 return S_OK;
[4837]2265}
2266
2267/******************************************************************************
[6711]2268 * VarUI1FromR8 [OLEAUT32.133]
[4837]2269 */
2270HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut)
2271{
[6711]2272 TRACE("( %f, %p ), stub\n", dblIn, pbOut );
[4837]2273
[6711]2274 /* Check range of value.
[4837]2275 */
[21916]2276 dblIn = rnd( dblIn );
[6711]2277 if( dblIn < UI1_MIN || dblIn > UI1_MAX )
2278 {
2279 return DISP_E_OVERFLOW;
2280 }
[4837]2281
[6711]2282 *pbOut = (BYTE) dblIn;
[4837]2283
[6711]2284 return S_OK;
[4837]2285}
2286
2287/******************************************************************************
[6711]2288 * VarUI1FromDate [OLEAUT32.135]
[4837]2289 */
2290HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut)
2291{
[6711]2292 TRACE("( %f, %p ), stub\n", dateIn, pbOut );
[4837]2293
[6711]2294 /* Check range of value.
[4837]2295 */
[21916]2296 dateIn = rnd( dateIn );
[6711]2297 if( dateIn < UI1_MIN || dateIn > UI1_MAX )
2298 {
2299 return DISP_E_OVERFLOW;
2300 }
[4837]2301
[6711]2302 *pbOut = (BYTE) dateIn;
[4837]2303
[6711]2304 return S_OK;
[4837]2305}
2306
2307/******************************************************************************
[6711]2308 * VarUI1FromBool [OLEAUT32.138]
[4837]2309 */
2310HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut)
2311{
[6711]2312 TRACE("( %d, %p ), stub\n", boolIn, pbOut );
[4837]2313
[6711]2314 *pbOut = (BYTE) boolIn;
[4837]2315
[6711]2316 return S_OK;
[4837]2317}
2318
2319/******************************************************************************
[6711]2320 * VarUI1FromI1 [OLEAUT32.237]
[4837]2321 */
2322HRESULT WINAPI VarUI1FromI1(CHAR cIn, BYTE* pbOut)
2323{
[6711]2324 TRACE("( %c, %p ), stub\n", cIn, pbOut );
[4837]2325
[6711]2326 *pbOut = cIn;
[4837]2327
[6711]2328 return S_OK;
[4837]2329}
2330
2331/******************************************************************************
[6711]2332 * VarUI1FromUI2 [OLEAUT32.238]
[4837]2333 */
2334HRESULT WINAPI VarUI1FromUI2(USHORT uiIn, BYTE* pbOut)
2335{
[6711]2336 TRACE("( %d, %p ), stub\n", uiIn, pbOut );
[4837]2337
[6711]2338 /* Check range of value.
2339 */
2340 if( uiIn > UI1_MAX )
2341 {
2342 return DISP_E_OVERFLOW;
2343 }
[4837]2344
[6711]2345 *pbOut = (BYTE) uiIn;
[4837]2346
[6711]2347 return S_OK;
[4837]2348}
2349
2350/******************************************************************************
[6711]2351 * VarUI1FromUI4 [OLEAUT32.239]
[4837]2352 */
2353HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut)
2354{
[6711]2355 TRACE("( %ld, %p ), stub\n", ulIn, pbOut );
[4837]2356
[6711]2357 /* Check range of value.
2358 */
2359 if( ulIn > UI1_MAX )
2360 {
2361 return DISP_E_OVERFLOW;
2362 }
[4837]2363
[6711]2364 *pbOut = (BYTE) ulIn;
[4837]2365
[6711]2366 return S_OK;
[4837]2367}
2368
2369
2370/******************************************************************************
[6711]2371 * VarUI1FromStr [OLEAUT32.136]
[4837]2372 */
2373HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut)
2374{
[6711]2375 double dValue = 0.0;
2376 LPSTR pNewString = NULL;
[4837]2377
[6711]2378 TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, pbOut );
[4837]2379
[6711]2380 /* Check if we have a valid argument
2381 */
2382 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2383 RemoveCharacterFromString( pNewString, "," );
2384 if( IsValidRealString( pNewString ) == FALSE )
2385 {
2386 return DISP_E_TYPEMISMATCH;
2387 }
[4837]2388
[6711]2389 /* Convert the valid string to a floating point number.
2390 */
2391 dValue = atof( pNewString );
[9400]2392
[6711]2393 /* We don't need the string anymore so free it.
2394 */
2395 HeapFree( GetProcessHeap(), 0 , pNewString );
[4837]2396
[6711]2397 /* Check range of value.
[4837]2398 */
[21916]2399 dValue = rnd( dValue );
[6711]2400 if( dValue < UI1_MIN || dValue > UI1_MAX )
2401 {
2402 return DISP_E_OVERFLOW;
2403 }
[4837]2404
[6711]2405 *pbOut = (BYTE) dValue;
[4837]2406
[6711]2407 return S_OK;
[4837]2408}
2409
2410/**********************************************************************
2411 * VarUI1FromCy [OLEAUT32.134]
2412 * Convert currency to unsigned char
2413 */
2414HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut) {
[21916]2415 double t = rnd((((double)cyIn.DUMMYSTRUCTNAME_DOT Hi * 4294967296.0) + (double)cyIn.DUMMYSTRUCTNAME_DOT Lo) / 10000);
[9400]2416
[4837]2417 if (t > UI1_MAX || t < UI1_MIN) return DISP_E_OVERFLOW;
[9400]2418
[4837]2419 *pbOut = (BYTE)t;
2420 return S_OK;
2421}
2422
2423/******************************************************************************
[6711]2424 * VarI2FromUI1 [OLEAUT32.48]
[4837]2425 */
2426HRESULT WINAPI VarI2FromUI1(BYTE bIn, short* psOut)
2427{
[6711]2428 TRACE("( 0x%08x, %p ), stub\n", bIn, psOut );
[4837]2429
[6711]2430 *psOut = (short) bIn;
[9400]2431
[6711]2432 return S_OK;
[4837]2433}
2434
2435/******************************************************************************
[6711]2436 * VarI2FromI4 [OLEAUT32.49]
[4837]2437 */
2438HRESULT WINAPI VarI2FromI4(LONG lIn, short* psOut)
2439{
[6711]2440 TRACE("( %lx, %p ), stub\n", lIn, psOut );
[4837]2441
[6711]2442 /* Check range of value.
2443 */
2444 if( lIn < I2_MIN || lIn > I2_MAX )
2445 {
2446 return DISP_E_OVERFLOW;
2447 }
[4837]2448
[6711]2449 *psOut = (short) lIn;
[9400]2450
[6711]2451 return S_OK;
[4837]2452}
2453
2454/******************************************************************************
[6711]2455 * VarI2FromR4 [OLEAUT32.50]
[4837]2456 */
2457HRESULT WINAPI VarI2FromR4(FLOAT fltIn, short* psOut)
2458{
[6711]2459 TRACE("( %f, %p ), stub\n", fltIn, psOut );
[4837]2460
[6711]2461 /* Check range of value.
[4837]2462 */
[21916]2463 fltIn = rnd( fltIn );
[6711]2464 if( fltIn < I2_MIN || fltIn > I2_MAX )
2465 {
2466 return DISP_E_OVERFLOW;
2467 }
[4837]2468
[6711]2469 *psOut = (short) fltIn;
[4837]2470
[6711]2471 return S_OK;
[4837]2472}
2473
2474/******************************************************************************
[6711]2475 * VarI2FromR8 [OLEAUT32.51]
[4837]2476 */
2477HRESULT WINAPI VarI2FromR8(double dblIn, short* psOut)
2478{
[6711]2479 TRACE("( %f, %p ), stub\n", dblIn, psOut );
[4837]2480
[6711]2481 /* Check range of value.
[4837]2482 */
[21916]2483 dblIn = rnd( dblIn );
[6711]2484 if( dblIn < I2_MIN || dblIn > I2_MAX )
2485 {
2486 return DISP_E_OVERFLOW;
2487 }
[4837]2488
[6711]2489 *psOut = (short) dblIn;
[4837]2490
[6711]2491 return S_OK;
[4837]2492}
2493
2494/******************************************************************************
[6711]2495 * VarI2FromDate [OLEAUT32.53]
[4837]2496 */
2497HRESULT WINAPI VarI2FromDate(DATE dateIn, short* psOut)
2498{
[6711]2499 TRACE("( %f, %p ), stub\n", dateIn, psOut );
[4837]2500
[6711]2501 /* Check range of value.
[4837]2502 */
[21916]2503 dateIn = rnd( dateIn );
[6711]2504 if( dateIn < I2_MIN || dateIn > I2_MAX )
2505 {
2506 return DISP_E_OVERFLOW;
2507 }
[4837]2508
[6711]2509 *psOut = (short) dateIn;
[4837]2510
[6711]2511 return S_OK;
[4837]2512}
2513
2514/******************************************************************************
[6711]2515 * VarI2FromBool [OLEAUT32.56]
[4837]2516 */
2517HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, short* psOut)
2518{
[6711]2519 TRACE("( %d, %p ), stub\n", boolIn, psOut );
[4837]2520
[6711]2521 *psOut = (short) boolIn;
[4837]2522
[6711]2523 return S_OK;
[4837]2524}
2525
2526/******************************************************************************
[6711]2527 * VarI2FromI1 [OLEAUT32.205]
[4837]2528 */
2529HRESULT WINAPI VarI2FromI1(CHAR cIn, short* psOut)
2530{
[6711]2531 TRACE("( %c, %p ), stub\n", cIn, psOut );
[4837]2532
[6711]2533 *psOut = (short) cIn;
[4837]2534
[6711]2535 return S_OK;
[4837]2536}
2537
2538/******************************************************************************
[6711]2539 * VarI2FromUI2 [OLEAUT32.206]
[4837]2540 */
2541HRESULT WINAPI VarI2FromUI2(USHORT uiIn, short* psOut)
2542{
[6711]2543 TRACE("( %d, %p ), stub\n", uiIn, psOut );
[4837]2544
[6711]2545 /* Check range of value.
2546 */
2547 if( uiIn > I2_MAX )
2548 {
2549 return DISP_E_OVERFLOW;
2550 }
[4837]2551
[6711]2552 *psOut = (short) uiIn;
[4837]2553
[6711]2554 return S_OK;
[4837]2555}
2556
2557/******************************************************************************
[6711]2558 * VarI2FromUI4 [OLEAUT32.207]
[4837]2559 */
2560HRESULT WINAPI VarI2FromUI4(ULONG ulIn, short* psOut)
2561{
[6711]2562 TRACE("( %lx, %p ), stub\n", ulIn, psOut );
[4837]2563
[6711]2564 /* Check range of value.
2565 */
2566 if( ulIn < I2_MIN || ulIn > I2_MAX )
2567 {
2568 return DISP_E_OVERFLOW;
2569 }
[4837]2570
[6711]2571 *psOut = (short) ulIn;
[4837]2572
[6711]2573 return S_OK;
[4837]2574}
2575
2576/******************************************************************************
[6711]2577 * VarI2FromStr [OLEAUT32.54]
[4837]2578 */
2579HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, short* psOut)
2580{
[6711]2581 double dValue = 0.0;
2582 LPSTR pNewString = NULL;
[4837]2583
[6711]2584 TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, psOut );
[4837]2585
[6711]2586 /* Check if we have a valid argument
2587 */
2588 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2589 RemoveCharacterFromString( pNewString, "," );
2590 if( IsValidRealString( pNewString ) == FALSE )
2591 {
2592 return DISP_E_TYPEMISMATCH;
2593 }
[4837]2594
[6711]2595 /* Convert the valid string to a floating point number.
2596 */
2597 dValue = atof( pNewString );
[9400]2598
[6711]2599 /* We don't need the string anymore so free it.
2600 */
2601 HeapFree( GetProcessHeap(), 0, pNewString );
[4837]2602
[6711]2603 /* Check range of value.
[4837]2604 */
[21916]2605 dValue = rnd( dValue );
[6711]2606 if( dValue < I2_MIN || dValue > I2_MAX )
2607 {
2608 return DISP_E_OVERFLOW;
2609 }
[4837]2610
[6711]2611 *psOut = (short) dValue;
[4837]2612
[6711]2613 return S_OK;
[4837]2614}
2615
2616/**********************************************************************
2617 * VarI2FromCy [OLEAUT32.52]
2618 * Convert currency to signed short
2619 */
2620HRESULT WINAPI VarI2FromCy(CY cyIn, short* psOut) {
[21916]2621 double t = rnd((((double)cyIn.DUMMYSTRUCTNAME_DOT Hi * 4294967296.0) + (double)cyIn.DUMMYSTRUCTNAME_DOT Lo) / 10000);
[9400]2622
[4837]2623 if (t > I2_MAX || t < I2_MIN) return DISP_E_OVERFLOW;
[9400]2624
[4837]2625 *psOut = (SHORT)t;
2626 return S_OK;
2627}
2628
2629/******************************************************************************
[6711]2630 * VarI4FromUI1 [OLEAUT32.58]
[4837]2631 */
2632HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG* plOut)
2633{
[6711]2634 TRACE("( %X, %p ), stub\n", bIn, plOut );
[4837]2635
[6711]2636 *plOut = (LONG) bIn;
[4837]2637
[6711]2638 return S_OK;
[4837]2639}
2640
2641
2642/******************************************************************************
[6711]2643 * VarI4FromR4 [OLEAUT32.60]
[4837]2644 */
2645HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG* plOut)
2646{
[6711]2647 TRACE("( %f, %p ), stub\n", fltIn, plOut );
[4837]2648
[6711]2649 /* Check range of value.
[4837]2650 */
[21916]2651 fltIn = rnd( fltIn );
[6711]2652 if( fltIn < I4_MIN || fltIn > I4_MAX )
2653 {
2654 return DISP_E_OVERFLOW;
2655 }
[4837]2656
[6711]2657 *plOut = (LONG) fltIn;
[4837]2658
[6711]2659 return S_OK;
[4837]2660}
2661
2662/******************************************************************************
[6711]2663 * VarI4FromR8 [OLEAUT32.61]
[4837]2664 */
2665HRESULT WINAPI VarI4FromR8(double dblIn, LONG* plOut)
2666{
[6711]2667 TRACE("( %f, %p ), stub\n", dblIn, plOut );
[4837]2668
[6711]2669 /* Check range of value.
[4837]2670 */
[21916]2671 dblIn = rnd( dblIn );
[6711]2672 if( dblIn < I4_MIN || dblIn > I4_MAX )
2673 {
2674 return DISP_E_OVERFLOW;
2675 }
[4837]2676
[6711]2677 *plOut = (LONG) dblIn;
[4837]2678
[6711]2679 return S_OK;
[4837]2680}
2681
2682/******************************************************************************
[6711]2683 * VarI4FromDate [OLEAUT32.63]
[4837]2684 */
2685HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG* plOut)
2686{
[6711]2687 TRACE("( %f, %p ), stub\n", dateIn, plOut );
[4837]2688
[6711]2689 /* Check range of value.
[4837]2690 */
[21916]2691 dateIn = rnd( dateIn );
[6711]2692 if( dateIn < I4_MIN || dateIn > I4_MAX )
2693 {
2694 return DISP_E_OVERFLOW;
2695 }
[4837]2696
[6711]2697 *plOut = (LONG) dateIn;
[4837]2698
[6711]2699 return S_OK;
[4837]2700}
2701
2702/******************************************************************************
[6711]2703 * VarI4FromBool [OLEAUT32.66]
[4837]2704 */
2705HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG* plOut)
2706{
[6711]2707 TRACE("( %d, %p ), stub\n", boolIn, plOut );
[4837]2708
[6711]2709 *plOut = (LONG) boolIn;
[4837]2710
[6711]2711 return S_OK;
[4837]2712}
2713
2714/******************************************************************************
[6711]2715 * VarI4FromI1 [OLEAUT32.209]
[4837]2716 */
2717HRESULT WINAPI VarI4FromI1(CHAR cIn, LONG* plOut)
2718{
[6711]2719 TRACE("( %c, %p ), stub\n", cIn, plOut );
[4837]2720
[6711]2721 *plOut = (LONG) cIn;
[4837]2722
[6711]2723 return S_OK;
[4837]2724}
2725
2726/******************************************************************************
[6711]2727 * VarI4FromUI2 [OLEAUT32.210]
[4837]2728 */
2729HRESULT WINAPI VarI4FromUI2(USHORT uiIn, LONG* plOut)
2730{
[6711]2731 TRACE("( %d, %p ), stub\n", uiIn, plOut );
[4837]2732
[6711]2733 *plOut = (LONG) uiIn;
[4837]2734
[6711]2735 return S_OK;
[4837]2736}
2737
2738/******************************************************************************
[6711]2739 * VarI4FromUI4 [OLEAUT32.211]
[4837]2740 */
2741HRESULT WINAPI VarI4FromUI4(ULONG ulIn, LONG* plOut)
2742{
[6711]2743 TRACE("( %lx, %p ), stub\n", ulIn, plOut );
[4837]2744
[6711]2745 /* Check range of value.
2746 */
2747 if( ulIn < I4_MIN || ulIn > I4_MAX )
2748 {
2749 return DISP_E_OVERFLOW;
2750 }
[4837]2751
[6711]2752 *plOut = (LONG) ulIn;
[4837]2753
[6711]2754 return S_OK;
[4837]2755}
2756
2757/******************************************************************************
[6711]2758 * VarI4FromI2 [OLEAUT32.59]
[4837]2759 */
2760HRESULT WINAPI VarI4FromI2(short sIn, LONG* plOut)
2761{
[6711]2762 TRACE("( %d, %p ), stub\n", sIn, plOut );
[4837]2763
[6711]2764 *plOut = (LONG) sIn;
[4837]2765
[6711]2766 return S_OK;
[4837]2767}
2768
2769/******************************************************************************
[6711]2770 * VarI4FromStr [OLEAUT32.64]
[4837]2771 */
2772HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG* plOut)
2773{
[6711]2774 double dValue = 0.0;
2775 LPSTR pNewString = NULL;
[4837]2776
[21308]2777 TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, plOut );
[4837]2778
[6711]2779 /* Check if we have a valid argument
2780 */
2781 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2782 RemoveCharacterFromString( pNewString, "," );
2783 if( IsValidRealString( pNewString ) == FALSE )
2784 {
2785 return DISP_E_TYPEMISMATCH;
2786 }
[4837]2787
[6711]2788 /* Convert the valid string to a floating point number.
2789 */
2790 dValue = atof( pNewString );
[9400]2791
[6711]2792 /* We don't need the string anymore so free it.
2793 */
2794 HeapFree( GetProcessHeap(), 0, pNewString );
[4837]2795
[6711]2796 /* Check range of value.
[4837]2797 */
[21916]2798 dValue = rnd( dValue );
[6711]2799 if( dValue < I4_MIN || dValue > I4_MAX )
2800 {
2801 return DISP_E_OVERFLOW;
2802 }
[4837]2803
[6711]2804 *plOut = (LONG) dValue;
[4837]2805
[6711]2806 return S_OK;
[4837]2807}
2808
2809/**********************************************************************
2810 * VarI4FromCy [OLEAUT32.62]
2811 * Convert currency to signed long
2812 */
2813HRESULT WINAPI VarI4FromCy(CY cyIn, LONG* plOut) {
[21916]2814 double t = rnd((((double)cyIn.DUMMYSTRUCTNAME_DOT Hi * 4294967296.0) + (double)cyIn.DUMMYSTRUCTNAME_DOT Lo) / 10000);
[9400]2815
[4837]2816 if (t > I4_MAX || t < I4_MIN) return DISP_E_OVERFLOW;
[9400]2817
[4837]2818 *plOut = (LONG)t;
2819 return S_OK;
2820}
2821
2822/******************************************************************************
[6711]2823 * VarR4FromUI1 [OLEAUT32.68]
[4837]2824 */
2825HRESULT WINAPI VarR4FromUI1(BYTE bIn, FLOAT* pfltOut)
2826{
[6711]2827 TRACE("( %X, %p ), stub\n", bIn, pfltOut );
[4837]2828
[6711]2829 *pfltOut = (FLOAT) bIn;
[4837]2830
[6711]2831 return S_OK;
[4837]2832}
2833
2834/******************************************************************************
[6711]2835 * VarR4FromI2 [OLEAUT32.69]
[4837]2836 */
2837HRESULT WINAPI VarR4FromI2(short sIn, FLOAT* pfltOut)
2838{
[6711]2839 TRACE("( %d, %p ), stub\n", sIn, pfltOut );
[4837]2840
[6711]2841 *pfltOut = (FLOAT) sIn;
[4837]2842
[6711]2843 return S_OK;
[4837]2844}
2845
2846/******************************************************************************
[6711]2847 * VarR4FromI4 [OLEAUT32.70]
[4837]2848 */
2849HRESULT WINAPI VarR4FromI4(LONG lIn, FLOAT* pfltOut)
2850{
[6711]2851 TRACE("( %lx, %p ), stub\n", lIn, pfltOut );
[4837]2852
[6711]2853 *pfltOut = (FLOAT) lIn;
[4837]2854
[6711]2855 return S_OK;
[4837]2856}
2857
2858/******************************************************************************
[6711]2859 * VarR4FromR8 [OLEAUT32.71]
[4837]2860 */
2861HRESULT WINAPI VarR4FromR8(double dblIn, FLOAT* pfltOut)
2862{
[6711]2863 TRACE("( %f, %p ), stub\n", dblIn, pfltOut );
[4837]2864
[6711]2865 /* Check range of value.
2866 */
2867 if( dblIn < -(FLT_MAX) || dblIn > FLT_MAX )
2868 {
2869 return DISP_E_OVERFLOW;
2870 }
[4837]2871
[6711]2872 *pfltOut = (FLOAT) dblIn;
[4837]2873
[6711]2874 return S_OK;
[4837]2875}
2876
2877/******************************************************************************
[6711]2878 * VarR4FromDate [OLEAUT32.73]
[4837]2879 */
2880HRESULT WINAPI VarR4FromDate(DATE dateIn, FLOAT* pfltOut)
2881{
[6711]2882 TRACE("( %f, %p ), stub\n", dateIn, pfltOut );
[4837]2883
[6711]2884 /* Check range of value.
2885 */
2886 if( dateIn < -(FLT_MAX) || dateIn > FLT_MAX )
2887 {
2888 return DISP_E_OVERFLOW;
2889 }
[4837]2890
[6711]2891 *pfltOut = (FLOAT) dateIn;
[4837]2892
[6711]2893 return S_OK;
[4837]2894}
2895
2896/******************************************************************************
[6711]2897 * VarR4FromBool [OLEAUT32.76]
[4837]2898 */
2899HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, FLOAT* pfltOut)
2900{
[6711]2901 TRACE("( %d, %p ), stub\n", boolIn, pfltOut );
[4837]2902
[6711]2903 *pfltOut = (FLOAT) boolIn;
[4837]2904
[6711]2905 return S_OK;
[4837]2906}
2907
2908/******************************************************************************
[6711]2909 * VarR4FromI1 [OLEAUT32.213]
[4837]2910 */
2911HRESULT WINAPI VarR4FromI1(CHAR cIn, FLOAT* pfltOut)
2912{
[6711]2913 TRACE("( %c, %p ), stub\n", cIn, pfltOut );
[4837]2914
[6711]2915 *pfltOut = (FLOAT) cIn;
[4837]2916
[6711]2917 return S_OK;
[4837]2918}
2919
2920/******************************************************************************
[6711]2921 * VarR4FromUI2 [OLEAUT32.214]
[4837]2922 */
2923HRESULT WINAPI VarR4FromUI2(USHORT uiIn, FLOAT* pfltOut)
2924{
[6711]2925 TRACE("( %d, %p ), stub\n", uiIn, pfltOut );
[4837]2926
[6711]2927 *pfltOut = (FLOAT) uiIn;
[4837]2928
[6711]2929 return S_OK;
[4837]2930}
2931
2932/******************************************************************************
[6711]2933 * VarR4FromUI4 [OLEAUT32.215]
[4837]2934 */
2935HRESULT WINAPI VarR4FromUI4(ULONG ulIn, FLOAT* pfltOut)
2936{
[6711]2937 TRACE("( %ld, %p ), stub\n", ulIn, pfltOut );
[4837]2938
[6711]2939 *pfltOut = (FLOAT) ulIn;
[4837]2940
[6711]2941 return S_OK;
[4837]2942}
2943
2944/******************************************************************************
[6711]2945 * VarR4FromStr [OLEAUT32.74]
[4837]2946 */
2947HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, FLOAT* pfltOut)
2948{
[6711]2949 double dValue = 0.0;
2950 LPSTR pNewString = NULL;
[4837]2951
[6711]2952 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pfltOut );
[4837]2953
[6711]2954 /* Check if we have a valid argument
2955 */
2956 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2957 RemoveCharacterFromString( pNewString, "," );
2958 if( IsValidRealString( pNewString ) == FALSE )
2959 {
2960 return DISP_E_TYPEMISMATCH;
2961 }
[4837]2962
[6711]2963 /* Convert the valid string to a floating point number.
2964 */
2965 dValue = atof( pNewString );
[9400]2966
[6711]2967 /* We don't need the string anymore so free it.
2968 */
2969 HeapFree( GetProcessHeap(), 0, pNewString );
[4837]2970
[6711]2971 /* Check range of value.
2972 */
2973 if( dValue < -(FLT_MAX) || dValue > FLT_MAX )
2974 {
2975 return DISP_E_OVERFLOW;
2976 }
[4837]2977
[6711]2978 *pfltOut = (FLOAT) dValue;
[4837]2979
[6711]2980 return S_OK;
[4837]2981}
2982
2983/**********************************************************************
2984 * VarR4FromCy [OLEAUT32.72]
2985 * Convert currency to float
2986 */
2987HRESULT WINAPI VarR4FromCy(CY cyIn, FLOAT* pfltOut) {
[21916]2988 *pfltOut = (FLOAT)((((double)cyIn.DUMMYSTRUCTNAME_DOT Hi * 4294967296.0) + (double)cyIn.DUMMYSTRUCTNAME_DOT Lo) / 10000);
[9400]2989
[4837]2990 return S_OK;
2991}
2992
2993/******************************************************************************
[6711]2994 * VarR8FromUI1 [OLEAUT32.78]
[4837]2995 */
2996HRESULT WINAPI VarR8FromUI1(BYTE bIn, double* pdblOut)
2997{
[6711]2998 TRACE("( %d, %p ), stub\n", bIn, pdblOut );
[4837]2999
[6711]3000 *pdblOut = (double) bIn;
[4837]3001
[6711]3002 return S_OK;
[4837]3003}
3004
3005/******************************************************************************
[6711]3006 * VarR8FromI2 [OLEAUT32.79]
[4837]3007 */
3008HRESULT WINAPI VarR8FromI2(short sIn, double* pdblOut)
3009{
[6711]3010 TRACE("( %d, %p ), stub\n", sIn, pdblOut );
[4837]3011
[6711]3012 *pdblOut = (double) sIn;
[4837]3013
[6711]3014 return S_OK;
[4837]3015}
3016
3017/******************************************************************************
[6711]3018 * VarR8FromI4 [OLEAUT32.80]
[4837]3019 */
3020HRESULT WINAPI VarR8FromI4(LONG lIn, double* pdblOut)
3021{
[6711]3022 TRACE("( %ld, %p ), stub\n", lIn, pdblOut );
[4837]3023
[6711]3024 *pdblOut = (double) lIn;
[4837]3025
[6711]3026 return S_OK;
[4837]3027}
3028
3029/******************************************************************************
[6711]3030 * VarR8FromR4 [OLEAUT32.81]
[4837]3031 */
3032HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double* pdblOut)
3033{
[6711]3034 TRACE("( %f, %p ), stub\n", fltIn, pdblOut );
[4837]3035
[6711]3036 *pdblOut = (double) fltIn;
[4837]3037
[6711]3038 return S_OK;
[4837]3039}
3040
3041/******************************************************************************
[6711]3042 * VarR8FromDate [OLEAUT32.83]
[4837]3043 */
3044HRESULT WINAPI VarR8FromDate(DATE dateIn, double* pdblOut)
3045{
[6711]3046 TRACE("( %f, %p ), stub\n", dateIn, pdblOut );
[4837]3047
[6711]3048 *pdblOut = (double) dateIn;
[4837]3049
[6711]3050 return S_OK;
[4837]3051}
3052
3053/******************************************************************************
[6711]3054 * VarR8FromBool [OLEAUT32.86]
[4837]3055 */
3056HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double* pdblOut)
3057{
[6711]3058 TRACE("( %d, %p ), stub\n", boolIn, pdblOut );
[4837]3059
[6711]3060 *pdblOut = (double) boolIn;
[4837]3061
[6711]3062 return S_OK;
[4837]3063}
3064
3065/******************************************************************************
[6711]3066 * VarR8FromI1 [OLEAUT32.217]
[4837]3067 */
3068HRESULT WINAPI VarR8FromI1(CHAR cIn, double* pdblOut)
3069{
[6711]3070 TRACE("( %c, %p ), stub\n", cIn, pdblOut );
[4837]3071
[6711]3072 *pdblOut = (double) cIn;
[4837]3073
[6711]3074 return S_OK;
[4837]3075}
3076
3077/******************************************************************************
[6711]3078 * VarR8FromUI2 [OLEAUT32.218]
[4837]3079 */
3080HRESULT WINAPI VarR8FromUI2(USHORT uiIn, double* pdblOut)
3081{
[6711]3082 TRACE("( %d, %p ), stub\n", uiIn, pdblOut );
[4837]3083
[6711]3084 *pdblOut = (double) uiIn;
[4837]3085
[6711]3086 return S_OK;
[4837]3087}
3088
3089/******************************************************************************
[6711]3090 * VarR8FromUI4 [OLEAUT32.219]
[4837]3091 */
3092HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double* pdblOut)
3093{
[6711]3094 TRACE("( %ld, %p ), stub\n", ulIn, pdblOut );
[4837]3095
[6711]3096 *pdblOut = (double) ulIn;
[4837]3097
[6711]3098 return S_OK;
[4837]3099}
3100
3101/******************************************************************************
[6711]3102 * VarR8FromStr [OLEAUT32.84]
[4837]3103 */
3104HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double* pdblOut)
3105{
[6711]3106 double dValue = 0.0;
3107 LPSTR pNewString = NULL;
[4837]3108
[9400]3109 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3110 TRACE("( %s, %ld, %ld, %p ), stub\n", pNewString, lcid, dwFlags, pdblOut );
[4837]3111
[6711]3112 /* Check if we have a valid argument
3113 */
3114 RemoveCharacterFromString( pNewString, "," );
3115 if( IsValidRealString( pNewString ) == FALSE )
3116 {
3117 return DISP_E_TYPEMISMATCH;
3118 }
[4837]3119
[6711]3120 /* Convert the valid string to a floating point number.
3121 */
3122 dValue = atof( pNewString );
[9400]3123
[6711]3124 /* We don't need the string anymore so free it.
3125 */
3126 HeapFree( GetProcessHeap(), 0, pNewString );
[4837]3127
[6711]3128 *pdblOut = dValue;
[4837]3129
[6711]3130 return S_OK;
[4837]3131}
3132
3133/**********************************************************************
3134 * VarR8FromCy [OLEAUT32.82]
3135 * Convert currency to double
3136 */
3137HRESULT WINAPI VarR8FromCy(CY cyIn, double* pdblOut) {
[21916]3138 *pdblOut = (double)((((double)cyIn.DUMMYSTRUCTNAME_DOT Hi * 4294967296.0) + (double)cyIn.DUMMYSTRUCTNAME_DOT Lo) / 10000);
3139 TRACE("%lu %ld -> %f\n", cyIn.DUMMYSTRUCTNAME_DOT Hi, cyIn.DUMMYSTRUCTNAME_DOT Lo, *pdblOut);
[4837]3140 return S_OK;
3141}
3142
3143/******************************************************************************
[6711]3144 * VarDateFromUI1 [OLEAUT32.88]
[4837]3145 */
3146HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
3147{
[6711]3148 TRACE("( %d, %p ), stub\n", bIn, pdateOut );
[4837]3149
[6711]3150 *pdateOut = (DATE) bIn;
[4837]3151
[6711]3152 return S_OK;
[4837]3153}
3154
3155/******************************************************************************
[6711]3156 * VarDateFromI2 [OLEAUT32.89]
[4837]3157 */
3158HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
3159{
[6711]3160 TRACE("( %d, %p ), stub\n", sIn, pdateOut );
[4837]3161
[6711]3162 *pdateOut = (DATE) sIn;
[4837]3163
[6711]3164 return S_OK;
[4837]3165}
3166
3167/******************************************************************************
[6711]3168 * VarDateFromI4 [OLEAUT32.90]
[4837]3169 */
3170HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
3171{
[6711]3172 TRACE("( %ld, %p ), stub\n", lIn, pdateOut );
[4837]3173
[6711]3174 if( lIn < DATE_MIN || lIn > DATE_MAX )
3175 {
3176 return DISP_E_OVERFLOW;
3177 }
[4837]3178
[6711]3179 *pdateOut = (DATE) lIn;
[4837]3180
[6711]3181 return S_OK;
[4837]3182}
3183
3184/******************************************************************************
[6711]3185 * VarDateFromR4 [OLEAUT32.91]
[4837]3186 */
3187HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
3188{
3189 TRACE("( %f, %p ), stub\n", fltIn, pdateOut );
3190
3191 if( ceil(fltIn) < DATE_MIN || floor(fltIn) > DATE_MAX )
[6711]3192 {
3193 return DISP_E_OVERFLOW;
3194 }
[4837]3195
[6711]3196 *pdateOut = (DATE) fltIn;
[4837]3197
[6711]3198 return S_OK;
[4837]3199}
3200
3201/******************************************************************************
[6711]3202 * VarDateFromR8 [OLEAUT32.92]
[4837]3203 */
3204HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
3205{
3206 TRACE("( %f, %p ), stub\n", dblIn, pdateOut );
3207
[6711]3208 if( ceil(dblIn) < DATE_MIN || floor(dblIn) > DATE_MAX )
3209 {
3210 return DISP_E_OVERFLOW;
3211 }
[4837]3212
[6711]3213 *pdateOut = (DATE) dblIn;
[4837]3214
[6711]3215 return S_OK;
[4837]3216}
3217
3218/******************************************************************************
[6711]3219 * VarDateFromStr [OLEAUT32.94]
[4837]3220 * The string representing the date is composed of two parts, a date and time.
3221 *
3222 * The format of the time is has follows:
3223 * hh[:mm][:ss][AM|PM]
3224 * Whitespace can be inserted anywhere between these tokens. A whitespace consists
3225 * of space and/or tab characters, which are ignored.
3226 *
3227 * The formats for the date part are has follows:
[9400]3228 * mm/[dd/][yy]yy
[4837]3229 * [dd/]mm/[yy]yy
[9400]3230 * [yy]yy/mm/dd
[4837]3231 * January dd[,] [yy]yy
3232 * dd January [yy]yy
3233 * [yy]yy January dd
3234 * Whitespace can be inserted anywhere between these tokens.
3235 *
3236 * The formats for the date and time string are has follows.
[9400]3237 * date[whitespace][time]
[4837]3238 * [time][whitespace]date
3239 *
3240 * These are the only characters allowed in a string representing a date and time:
3241 * [A-Z] [a-z] [0-9] ':' '-' '/' ',' ' ' '\t'
3242 */
3243HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
3244{
3245 HRESULT ret = S_OK;
3246 struct tm TM;
3247
3248 memset( &TM, 0, sizeof(TM) );
3249
3250 TRACE("( %p, %lx, %lx, %p ), stub\n", strIn, lcid, dwFlags, pdateOut );
3251
[6575]3252 if( DateTimeStringToTm( strIn, dwFlags, &TM ) )
[4837]3253 {
3254 if( TmToDATE( &TM, pdateOut ) == FALSE )
3255 {
3256 ret = E_INVALIDARG;
3257 }
3258 }
3259 else
3260 {
3261 ret = DISP_E_TYPEMISMATCH;
3262 }
[9400]3263 TRACE("Return value %f\n", *pdateOut);
[6711]3264 return ret;
[4837]3265}
3266
3267/******************************************************************************
[6711]3268 * VarDateFromI1 [OLEAUT32.221]
[4837]3269 */
3270HRESULT WINAPI VarDateFromI1(CHAR cIn, DATE* pdateOut)
3271{
[6711]3272 TRACE("( %c, %p ), stub\n", cIn, pdateOut );
[4837]3273
[6711]3274 *pdateOut = (DATE) cIn;
[4837]3275
[6711]3276 return S_OK;
[4837]3277}
3278
3279/******************************************************************************
[6711]3280 * VarDateFromUI2 [OLEAUT32.222]
[4837]3281 */
3282HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
3283{
[6711]3284 TRACE("( %d, %p ), stub\n", uiIn, pdateOut );
[4837]3285
[6711]3286 if( uiIn > DATE_MAX )
3287 {
3288 return DISP_E_OVERFLOW;
3289 }
[4837]3290
[6711]3291 *pdateOut = (DATE) uiIn;
[4837]3292
[6711]3293 return S_OK;
[4837]3294}
3295
3296/******************************************************************************
[6711]3297 * VarDateFromUI4 [OLEAUT32.223]
[4837]3298 */
3299HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
3300{
[6711]3301 TRACE("( %ld, %p ), stub\n", ulIn, pdateOut );
[4837]3302
[6711]3303 if( ulIn < DATE_MIN || ulIn > DATE_MAX )
3304 {
3305 return DISP_E_OVERFLOW;
3306 }
[4837]3307
[6711]3308 *pdateOut = (DATE) ulIn;
[4837]3309
[6711]3310 return S_OK;
[4837]3311}
3312
3313/******************************************************************************
[6711]3314 * VarDateFromBool [OLEAUT32.96]
[4837]3315 */
3316HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
3317{
[6711]3318 TRACE("( %d, %p ), stub\n", boolIn, pdateOut );
[4837]3319
[6711]3320 *pdateOut = (DATE) boolIn;
[4837]3321
[6711]3322 return S_OK;
[4837]3323}
3324
3325/**********************************************************************
3326 * VarDateFromCy [OLEAUT32.93]
3327 * Convert currency to date
3328 */
3329HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut) {
[21916]3330 *pdateOut = (DATE)((((double)cyIn.DUMMYSTRUCTNAME_DOT Hi * 4294967296.0) + (double)cyIn.DUMMYSTRUCTNAME_DOT Lo) / 10000);
[4837]3331
3332 if (*pdateOut > DATE_MAX || *pdateOut < DATE_MIN) return DISP_E_TYPEMISMATCH;
3333 return S_OK;
3334}
3335
3336/******************************************************************************
[6711]3337 * VarBstrFromUI1 [OLEAUT32.108]
[4837]3338 */
3339HRESULT WINAPI VarBstrFromUI1(BYTE bVal, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3340{
[6711]3341 TRACE("( %d, %ld, %ld, %p ), stub\n", bVal, lcid, dwFlags, pbstrOut );
3342 sprintf( pBuffer, "%d", bVal );
[4837]3343
[6711]3344 *pbstrOut = StringDupAtoBstr( pBuffer );
[9400]3345
[6711]3346 return S_OK;
[4837]3347}
3348
3349/******************************************************************************
[6711]3350 * VarBstrFromI2 [OLEAUT32.109]
[4837]3351 */
3352HRESULT WINAPI VarBstrFromI2(short iVal, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3353{
[6711]3354 TRACE("( %d, %ld, %ld, %p ), stub\n", iVal, lcid, dwFlags, pbstrOut );
3355 sprintf( pBuffer, "%d", iVal );
3356 *pbstrOut = StringDupAtoBstr( pBuffer );
[4837]3357
[6711]3358 return S_OK;
[4837]3359}
3360
3361/******************************************************************************
[6711]3362 * VarBstrFromI4 [OLEAUT32.110]
[4837]3363 */
3364HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3365{
[6711]3366 TRACE("( %ld, %ld, %ld, %p ), stub\n", lIn, lcid, dwFlags, pbstrOut );
[4837]3367
[6711]3368 sprintf( pBuffer, "%ld", lIn );
3369 *pbstrOut = StringDupAtoBstr( pBuffer );
[4837]3370
[6711]3371 return S_OK;
[4837]3372}
3373
3374/******************************************************************************
[6711]3375 * VarBstrFromR4 [OLEAUT32.111]
[4837]3376 */
3377HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3378{
[6711]3379 TRACE("( %f, %ld, %ld, %p ), stub\n", fltIn, lcid, dwFlags, pbstrOut );
[4837]3380
[6711]3381 sprintf( pBuffer, "%.7g", fltIn );
3382 *pbstrOut = StringDupAtoBstr( pBuffer );
[4837]3383
[6711]3384 return S_OK;
[4837]3385}
3386
3387/******************************************************************************
[6711]3388 * VarBstrFromR8 [OLEAUT32.112]
[4837]3389 */
3390HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3391{
[6711]3392 TRACE("( %f, %ld, %ld, %p ), stub\n", dblIn, lcid, dwFlags, pbstrOut );
[4837]3393
[6711]3394 sprintf( pBuffer, "%.15g", dblIn );
3395 *pbstrOut = StringDupAtoBstr( pBuffer );
[4837]3396
[6711]3397 return S_OK;
[4837]3398}
3399
3400/******************************************************************************
3401 * VarBstrFromCy [OLEAUT32.113]
3402 */
3403HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut) {
[9400]3404 HRESULT rc = S_OK;
3405 double curVal = 0.0;
3406
3407 TRACE("([cyIn], %08lx, %08lx, %p), partial stub (no flags handled).\n", lcid, dwFlags, pbstrOut);
3408
3409 /* Firstly get the currency in a double, then put it in a buffer */
3410 rc = VarR8FromCy(cyIn, &curVal);
3411 if (rc == S_OK) {
3412 sprintf(pBuffer, "%g", curVal);
3413 *pbstrOut = StringDupAtoBstr( pBuffer );
3414 }
3415 return rc;
[4837]3416}
3417
[9400]3418
[4837]3419/******************************************************************************
[6711]3420 * VarBstrFromDate [OLEAUT32.114]
[4837]3421 *
3422 * The date is implemented using an 8 byte floating-point number.
[6575]3423 * Days are represented by whole numbers increments starting with 0.00 as
[4837]3424 * being December 30 1899, midnight.
3425 * The hours are expressed as the fractional part of the number.
3426 * December 30 1899 at midnight = 0.00
3427 * January 1 1900 at midnight = 2.00
3428 * January 4 1900 at 6 AM = 5.25
3429 * January 4 1900 at noon = 5.50
3430 * December 29 1899 at midnight = -1.00
3431 * December 18 1899 at midnight = -12.00
3432 * December 18 1899 at 6AM = -12.25
3433 * December 18 1899 at 6PM = -12.75
3434 * December 19 1899 at midnight = -11.00
3435 * The tm structure is as follows:
3436 * struct tm {
[6711]3437 * int tm_sec; seconds after the minute - [0,59]
3438 * int tm_min; minutes after the hour - [0,59]
3439 * int tm_hour; hours since midnight - [0,23]
3440 * int tm_mday; day of the month - [1,31]
3441 * int tm_mon; months since January - [0,11]
3442 * int tm_year; years
3443 * int tm_wday; days since Sunday - [0,6]
3444 * int tm_yday; days since January 1 - [0,365]
3445 * int tm_isdst; daylight savings time flag
3446 * };
[4837]3447 */
3448HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3449{
3450 struct tm TM;
3451 memset( &TM, 0, sizeof(TM) );
3452
[9400]3453 TRACE("( %20.20f, %ld, %ld, %p ), stub\n", dateIn, lcid, dwFlags, pbstrOut );
[4837]3454
[6575]3455 if( DateToTm( dateIn, dwFlags, &TM ) == FALSE )
[6711]3456 {
[4837]3457 return E_INVALIDARG;
[6711]3458 }
[4837]3459
3460 if( dwFlags & VAR_DATEVALUEONLY )
[6711]3461 strftime( pBuffer, BUFFER_MAX, "%x", &TM );
[4837]3462 else if( dwFlags & VAR_TIMEVALUEONLY )
[6711]3463 strftime( pBuffer, BUFFER_MAX, "%X", &TM );
3464 else
[4837]3465 strftime( pBuffer, BUFFER_MAX, "%x %X", &TM );
3466
[9400]3467 TRACE("result: %s\n", pBuffer);
[6711]3468 *pbstrOut = StringDupAtoBstr( pBuffer );
3469 return S_OK;
[4837]3470}
3471
3472/******************************************************************************
[6711]3473 * VarBstrFromBool [OLEAUT32.116]
[4837]3474 */
3475HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3476{
[6711]3477 TRACE("( %d, %ld, %ld, %p ), stub\n", boolIn, lcid, dwFlags, pbstrOut );
[4837]3478
[6944]3479 sprintf( pBuffer, (boolIn == VARIANT_FALSE) ? "False" : "True" );
[4837]3480
[6711]3481 *pbstrOut = StringDupAtoBstr( pBuffer );
[4837]3482
[6711]3483 return S_OK;
[4837]3484}
3485
3486/******************************************************************************
[6711]3487 * VarBstrFromI1 [OLEAUT32.229]
[4837]3488 */
3489HRESULT WINAPI VarBstrFromI1(CHAR cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3490{
[6711]3491 TRACE("( %c, %ld, %ld, %p ), stub\n", cIn, lcid, dwFlags, pbstrOut );
3492 sprintf( pBuffer, "%d", cIn );
3493 *pbstrOut = StringDupAtoBstr( pBuffer );
[4837]3494
[6711]3495 return S_OK;
[4837]3496}
3497
3498/******************************************************************************
[6711]3499 * VarBstrFromUI2 [OLEAUT32.230]
[4837]3500 */
3501HRESULT WINAPI VarBstrFromUI2(USHORT uiIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3502{
[6711]3503 TRACE("( %d, %ld, %ld, %p ), stub\n", uiIn, lcid, dwFlags, pbstrOut );
3504 sprintf( pBuffer, "%d", uiIn );
3505 *pbstrOut = StringDupAtoBstr( pBuffer );
[4837]3506
[6711]3507 return S_OK;
[4837]3508}
3509
3510/******************************************************************************
[6711]3511 * VarBstrFromUI4 [OLEAUT32.231]
[4837]3512 */
3513HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3514{
[6711]3515 TRACE("( %ld, %ld, %ld, %p ), stub\n", ulIn, lcid, dwFlags, pbstrOut );
3516 sprintf( pBuffer, "%ld", ulIn );
3517 *pbstrOut = StringDupAtoBstr( pBuffer );
[4837]3518
[6711]3519 return S_OK;
[4837]3520}
3521
3522/******************************************************************************
[6711]3523 * VarBoolFromUI1 [OLEAUT32.118]
[4837]3524 */
3525HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL* pboolOut)
3526{
[6711]3527 TRACE("( %d, %p ), stub\n", bIn, pboolOut );
[4837]3528
[6711]3529 if( bIn == 0 )
3530 {
3531 *pboolOut = VARIANT_FALSE;
3532 }
3533 else
3534 {
3535 *pboolOut = VARIANT_TRUE;
3536 }
[4837]3537
[6711]3538 return S_OK;
[4837]3539}
3540
3541/******************************************************************************
[6711]3542 * VarBoolFromI2 [OLEAUT32.119]
[4837]3543 */
3544HRESULT WINAPI VarBoolFromI2(short sIn, VARIANT_BOOL* pboolOut)
3545{
[6711]3546 TRACE("( %d, %p ), stub\n", sIn, pboolOut );
[4837]3547
[6944]3548 *pboolOut = (sIn) ? VARIANT_TRUE : VARIANT_FALSE;
[4837]3549
[6711]3550 return S_OK;
[4837]3551}
3552
3553/******************************************************************************
[6711]3554 * VarBoolFromI4 [OLEAUT32.120]
[4837]3555 */
3556HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL* pboolOut)
3557{
[6711]3558 TRACE("( %ld, %p ), stub\n", lIn, pboolOut );
[4837]3559
[6944]3560 *pboolOut = (lIn) ? VARIANT_TRUE : VARIANT_FALSE;
[4837]3561
[6711]3562 return S_OK;
[4837]3563}
3564
3565/******************************************************************************
[6711]3566 * VarBoolFromR4 [OLEAUT32.121]
[4837]3567 */
3568HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL* pboolOut)
3569{
[6711]3570 TRACE("( %f, %p ), stub\n", fltIn, pboolOut );
[4837]3571
[6944]3572 *pboolOut = (fltIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
[4837]3573
[6711]3574 return S_OK;
[4837]3575}
3576
3577/******************************************************************************
[6711]3578 * VarBoolFromR8 [OLEAUT32.122]
[4837]3579 */
3580HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL* pboolOut)
3581{
[6711]3582 TRACE("( %f, %p ), stub\n", dblIn, pboolOut );
[4837]3583
[6944]3584 *pboolOut = (dblIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
[4837]3585
[6711]3586 return S_OK;
[4837]3587}
3588
3589/******************************************************************************
[6711]3590 * VarBoolFromDate [OLEAUT32.123]
[4837]3591 */
3592HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL* pboolOut)
3593{
[6711]3594 TRACE("( %f, %p ), stub\n", dateIn, pboolOut );
[4837]3595
[6944]3596 *pboolOut = (dateIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
[4837]3597
[6711]3598 return S_OK;
[4837]3599}
3600
3601/******************************************************************************
[6711]3602 * VarBoolFromStr [OLEAUT32.125]
[4837]3603 */
3604HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL* pboolOut)
3605{
[6711]3606 HRESULT ret = S_OK;
3607 char* pNewString = NULL;
[4837]3608
[6711]3609 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pboolOut );
[4837]3610
3611 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3612
[6711]3613 if( pNewString == NULL || strlen( pNewString ) == 0 )
3614 {
3615 ret = DISP_E_TYPEMISMATCH;
3616 }
[4837]3617
[6711]3618 if( ret == S_OK )
3619 {
3620 if( strncasecmp( pNewString, "True", strlen( pNewString ) ) == 0 )
3621 {
3622 *pboolOut = VARIANT_TRUE;
3623 }
3624 else if( strncasecmp( pNewString, "False", strlen( pNewString ) ) == 0 )
3625 {
3626 *pboolOut = VARIANT_FALSE;
3627 }
3628 else
3629 {
3630 /* Try converting the string to a floating point number.
3631 */
3632 double dValue = 0.0;
3633 HRESULT res = VarR8FromStr( strIn, lcid, dwFlags, &dValue );
3634 if( res != S_OK )
3635 {
3636 ret = DISP_E_TYPEMISMATCH;
3637 }
3638 else
[6944]3639 *pboolOut = (dValue == 0.0) ?
3640 VARIANT_FALSE : VARIANT_TRUE;
[6711]3641 }
3642 }
[4837]3643
[6711]3644 HeapFree( GetProcessHeap(), 0, pNewString );
[9400]3645
[6711]3646 return ret;
[4837]3647}
3648
3649/******************************************************************************
[6711]3650 * VarBoolFromI1 [OLEAUT32.233]
[4837]3651 */
3652HRESULT WINAPI VarBoolFromI1(CHAR cIn, VARIANT_BOOL* pboolOut)
3653{
[6711]3654 TRACE("( %c, %p ), stub\n", cIn, pboolOut );
[4837]3655
[6944]3656 *pboolOut = (cIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
[4837]3657
[6711]3658 return S_OK;
[4837]3659}
3660
3661/******************************************************************************
[6711]3662 * VarBoolFromUI2 [OLEAUT32.234]
[4837]3663 */
3664HRESULT WINAPI VarBoolFromUI2(USHORT uiIn, VARIANT_BOOL* pboolOut)
3665{
[6711]3666 TRACE("( %d, %p ), stub\n", uiIn, pboolOut );
[4837]3667
[6944]3668 *pboolOut = (uiIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
[4837]3669
[6711]3670 return S_OK;
[4837]3671}
3672
3673/******************************************************************************
[6711]3674 * VarBoolFromUI4 [OLEAUT32.235]
[4837]3675 */
3676HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL* pboolOut)
3677{
[6711]3678 TRACE("( %ld, %p ), stub\n", ulIn, pboolOut );
[4837]3679
[6944]3680 *pboolOut = (ulIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
[4837]3681
[6711]3682 return S_OK;
[4837]3683}
3684
3685/**********************************************************************
3686 * VarBoolFromCy [OLEAUT32.124]
3687 * Convert currency to boolean
3688 */
3689HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL* pboolOut) {
[21916]3690 if (cyIn.DUMMYSTRUCTNAME_DOT Hi || cyIn.DUMMYSTRUCTNAME_DOT Lo) *pboolOut = -1;
[4837]3691 else *pboolOut = 0;
[9400]3692
[4837]3693 return S_OK;
3694}
3695
3696/******************************************************************************
[6711]3697 * VarI1FromUI1 [OLEAUT32.244]
[4837]3698 */
3699HRESULT WINAPI VarI1FromUI1(BYTE bIn, CHAR* pcOut)
3700{
[6711]3701 TRACE("( %d, %p ), stub\n", bIn, pcOut );
[4837]3702
[6711]3703 /* Check range of value.
3704 */
3705 if( bIn > CHAR_MAX )
3706 {
3707 return DISP_E_OVERFLOW;
3708 }
[4837]3709
[6711]3710 *pcOut = (CHAR) bIn;
[4837]3711
[6711]3712 return S_OK;
[4837]3713}
3714
3715/******************************************************************************
[6711]3716 * VarI1FromI2 [OLEAUT32.245]
[4837]3717 */
3718HRESULT WINAPI VarI1FromI2(short uiIn, CHAR* pcOut)
3719{
[6711]3720 TRACE("( %d, %p ), stub\n", uiIn, pcOut );
[4837]3721
[6711]3722 if( uiIn > CHAR_MAX )
3723 {
3724 return DISP_E_OVERFLOW;
3725 }
[4837]3726
[6711]3727 *pcOut = (CHAR) uiIn;
[4837]3728
[6711]3729 return S_OK;
[4837]3730}
3731
3732/******************************************************************************
[6711]3733 * VarI1FromI4 [OLEAUT32.246]
[4837]3734 */
3735HRESULT WINAPI VarI1FromI4(LONG lIn, CHAR* pcOut)
3736{
[6711]3737 TRACE("( %ld, %p ), stub\n", lIn, pcOut );
[4837]3738
[6711]3739 if( lIn < CHAR_MIN || lIn > CHAR_MAX )
3740 {
3741 return DISP_E_OVERFLOW;
3742 }
[4837]3743
[6711]3744 *pcOut = (CHAR) lIn;
[4837]3745
[6711]3746 return S_OK;
[4837]3747}
3748
3749/******************************************************************************
[6711]3750 * VarI1FromR4 [OLEAUT32.247]
[4837]3751 */
3752HRESULT WINAPI VarI1FromR4(FLOAT fltIn, CHAR* pcOut)
3753{
[6711]3754 TRACE("( %f, %p ), stub\n", fltIn, pcOut );
[4837]3755
[21916]3756 fltIn = rnd( fltIn );
[6711]3757 if( fltIn < CHAR_MIN || fltIn > CHAR_MAX )
3758 {
3759 return DISP_E_OVERFLOW;
3760 }
[4837]3761
[6711]3762 *pcOut = (CHAR) fltIn;
[4837]3763
[6711]3764 return S_OK;
[4837]3765}
3766
3767/******************************************************************************
[6711]3768 * VarI1FromR8 [OLEAUT32.248]
[4837]3769 */
3770HRESULT WINAPI VarI1FromR8(double dblIn, CHAR* pcOut)
3771{
[6711]3772 TRACE("( %f, %p ), stub\n", dblIn, pcOut );
[4837]3773
[21916]3774 dblIn = rnd( dblIn );
[4837]3775 if( dblIn < CHAR_MIN || dblIn > CHAR_MAX )
[6711]3776 {
3777 return DISP_E_OVERFLOW;
3778 }
[4837]3779
[6711]3780 *pcOut = (CHAR) dblIn;
[4837]3781
[6711]3782 return S_OK;
[4837]3783}
3784
3785/******************************************************************************
[6711]3786 * VarI1FromDate [OLEAUT32.249]
[4837]3787 */
3788HRESULT WINAPI VarI1FromDate(DATE dateIn, CHAR* pcOut)
3789{
[6711]3790 TRACE("( %f, %p ), stub\n", dateIn, pcOut );
[4837]3791
[21916]3792 dateIn = rnd( dateIn );
[6711]3793 if( dateIn < CHAR_MIN || dateIn > CHAR_MAX )
3794 {
3795 return DISP_E_OVERFLOW;
3796 }
[4837]3797
[6711]3798 *pcOut = (CHAR) dateIn;
[4837]3799
[6711]3800 return S_OK;
[4837]3801}
3802
3803/******************************************************************************
[6711]3804 * VarI1FromStr [OLEAUT32.251]
[4837]3805 */
3806HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, CHAR* pcOut)
3807{
[6711]3808 double dValue = 0.0;
3809 LPSTR pNewString = NULL;
[4837]3810
[6711]3811 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pcOut );
[4837]3812
[6711]3813 /* Check if we have a valid argument
3814 */
3815 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3816 RemoveCharacterFromString( pNewString, "," );
3817 if( IsValidRealString( pNewString ) == FALSE )
3818 {
3819 return DISP_E_TYPEMISMATCH;
3820 }
[4837]3821
[6711]3822 /* Convert the valid string to a floating point number.
3823 */
3824 dValue = atof( pNewString );
[9400]3825
[6711]3826 /* We don't need the string anymore so free it.
3827 */
3828 HeapFree( GetProcessHeap(), 0, pNewString );
[4837]3829
[6711]3830 /* Check range of value.
[4837]3831 */
[21916]3832 dValue = rnd( dValue );
[6711]3833 if( dValue < CHAR_MIN || dValue > CHAR_MAX )
3834 {
3835 return DISP_E_OVERFLOW;
3836 }
[4837]3837
[6711]3838 *pcOut = (CHAR) dValue;
[4837]3839
[6711]3840 return S_OK;
[4837]3841}
3842
3843/******************************************************************************
[6711]3844 * VarI1FromBool [OLEAUT32.253]
[4837]3845 */
3846HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, CHAR* pcOut)
3847{
[6711]3848 TRACE("( %d, %p ), stub\n", boolIn, pcOut );
[4837]3849
[6711]3850 *pcOut = (CHAR) boolIn;
[4837]3851
[6711]3852 return S_OK;
[4837]3853}
3854
3855/******************************************************************************
[6711]3856 * VarI1FromUI2 [OLEAUT32.254]
[4837]3857 */
3858HRESULT WINAPI VarI1FromUI2(USHORT uiIn, CHAR* pcOut)
3859{
[6711]3860 TRACE("( %d, %p ), stub\n", uiIn, pcOut );
[4837]3861
[6711]3862 if( uiIn > CHAR_MAX )
3863 {
3864 return DISP_E_OVERFLOW;
3865 }
[4837]3866
[6711]3867 *pcOut = (CHAR) uiIn;
[4837]3868
[6711]3869 return S_OK;
[4837]3870}
3871
3872/******************************************************************************
[6711]3873 * VarI1FromUI4 [OLEAUT32.255]
[4837]3874 */
3875HRESULT WINAPI VarI1FromUI4(ULONG ulIn, CHAR* pcOut)
3876{
[6711]3877 TRACE("( %ld, %p ), stub\n", ulIn, pcOut );
[4837]3878
[6711]3879 if( ulIn > CHAR_MAX )
3880 {
3881 return DISP_E_OVERFLOW;
3882 }
[4837]3883
[6711]3884 *pcOut = (CHAR) ulIn;
[4837]3885
[6711]3886 return S_OK;
[4837]3887}
3888
3889/**********************************************************************
3890 * VarI1FromCy [OLEAUT32.250]
3891 * Convert currency to signed char
3892 */
3893HRESULT WINAPI VarI1FromCy(CY cyIn, CHAR* pcOut) {
[21916]3894 double t = rnd((((double)cyIn.DUMMYSTRUCTNAME_DOT Hi * 4294967296.0) + (double)cyIn.DUMMYSTRUCTNAME_DOT Lo) / 10000);
[9400]3895
[4837]3896 if (t > CHAR_MAX || t < CHAR_MIN) return DISP_E_OVERFLOW;
[9400]3897
[4837]3898 *pcOut = (CHAR)t;
3899 return S_OK;
3900}
3901
3902/******************************************************************************
[6711]3903 * VarUI2FromUI1 [OLEAUT32.257]
[4837]3904 */
3905HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* puiOut)
3906{
[6711]3907 TRACE("( %d, %p ), stub\n", bIn, puiOut );
[4837]3908
[6711]3909 *puiOut = (USHORT) bIn;
[4837]3910
[6711]3911 return S_OK;
[4837]3912}
3913
3914/******************************************************************************
[6711]3915 * VarUI2FromI2 [OLEAUT32.258]
[4837]3916 */
3917HRESULT WINAPI VarUI2FromI2(short uiIn, USHORT* puiOut)
3918{
[6711]3919 TRACE("( %d, %p ), stub\n", uiIn, puiOut );
[4837]3920
[6711]3921 if( uiIn < UI2_MIN )
3922 {
3923 return DISP_E_OVERFLOW;
3924 }
[4837]3925
[6711]3926 *puiOut = (USHORT) uiIn;
[4837]3927
[6711]3928 return S_OK;
[4837]3929}
3930
3931/******************************************************************************
[6711]3932 * VarUI2FromI4 [OLEAUT32.259]
[4837]3933 */
3934HRESULT WINAPI VarUI2FromI4(LONG lIn, USHORT* puiOut)
3935{
[6711]3936 TRACE("( %ld, %p ), stub\n", lIn, puiOut );
[4837]3937
[6711]3938 if( lIn < UI2_MIN || lIn > UI2_MAX )
3939 {
3940 return DISP_E_OVERFLOW;
3941 }
[4837]3942
[6711]3943 *puiOut = (USHORT) lIn;
[4837]3944
[6711]3945 return S_OK;
[4837]3946}
3947
3948/******************************************************************************
[6711]3949 * VarUI2FromR4 [OLEAUT32.260]
[4837]3950 */
3951HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* puiOut)
3952{
[6711]3953 TRACE("( %f, %p ), stub\n", fltIn, puiOut );
[4837]3954
[21916]3955 fltIn = rnd( fltIn );
[6711]3956 if( fltIn < UI2_MIN || fltIn > UI2_MAX )
3957 {
3958 return DISP_E_OVERFLOW;
3959 }
[4837]3960
[6711]3961 *puiOut = (USHORT) fltIn;
[4837]3962
[6711]3963 return S_OK;
[4837]3964}
3965
3966/******************************************************************************
[6711]3967 * VarUI2FromR8 [OLEAUT32.261]
[4837]3968 */
3969HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* puiOut)
3970{
[6711]3971 TRACE("( %f, %p ), stub\n", dblIn, puiOut );
[4837]3972
[21916]3973 dblIn = rnd( dblIn );
[4837]3974 if( dblIn < UI2_MIN || dblIn > UI2_MAX )
[6711]3975 {
3976 return DISP_E_OVERFLOW;
3977 }
[4837]3978
[6711]3979 *puiOut = (USHORT) dblIn;
[4837]3980
[6711]3981 return S_OK;
[4837]3982}
3983
3984/******************************************************************************
[6711]3985 * VarUI2FromDate [OLEAUT32.262]
[4837]3986 */
3987HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* puiOut)
3988{
[6711]3989 TRACE("( %f, %p ), stub\n", dateIn, puiOut );
[4837]3990
[21916]3991 dateIn = rnd( dateIn );
[6711]3992 if( dateIn < UI2_MIN || dateIn > UI2_MAX )
3993 {
3994 return DISP_E_OVERFLOW;
3995 }
[4837]3996
[6711]3997 *puiOut = (USHORT) dateIn;
[4837]3998
[6711]3999 return S_OK;
[4837]4000}
4001
4002/******************************************************************************
[6711]4003 * VarUI2FromStr [OLEAUT32.264]
[4837]4004 */
4005HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* puiOut)
4006{
[6711]4007 double dValue = 0.0;
4008 LPSTR pNewString = NULL;
[4837]4009
[6711]4010 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, puiOut );
[4837]4011
[6711]4012 /* Check if we have a valid argument
4013 */
4014 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
4015 RemoveCharacterFromString( pNewString, "," );
4016 if( IsValidRealString( pNewString ) == FALSE )
4017 {
4018 return DISP_E_TYPEMISMATCH;
4019 }
[4837]4020
[6711]4021 /* Convert the valid string to a floating point number.
4022 */
4023 dValue = atof( pNewString );
[9400]4024
[6711]4025 /* We don't need the string anymore so free it.
4026 */
4027 HeapFree( GetProcessHeap(), 0, pNewString );
[4837]4028
[6711]4029 /* Check range of value.
[4837]4030 */
[21916]4031 dValue = rnd( dValue );
[6711]4032 if( dValue < UI2_MIN || dValue > UI2_MAX )
4033 {
4034 return DISP_E_OVERFLOW;
4035 }
[4837]4036
[6711]4037 *puiOut = (USHORT) dValue;
[4837]4038
[6711]4039 return S_OK;
[4837]4040}
4041
4042/******************************************************************************
[6711]4043 * VarUI2FromBool [OLEAUT32.266]
[4837]4044 */
4045HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* puiOut)
4046{
[6711]4047 TRACE("( %d, %p ), stub\n", boolIn, puiOut );
[4837]4048
[6711]4049 *puiOut = (USHORT) boolIn;
[4837]4050
[6711]4051 return S_OK;
[4837]4052}
4053
4054/******************************************************************************
[6711]4055 * VarUI2FromI1 [OLEAUT32.267]
[4837]4056 */
4057HRESULT WINAPI VarUI2FromI1(CHAR cIn, USHORT* puiOut)
4058{
[6711]4059 TRACE("( %c, %p ), stub\n", cIn, puiOut );
[4837]4060
[6711]4061 *puiOut = (USHORT) cIn;
[4837]4062
[6711]4063 return S_OK;
[4837]4064}
4065
4066/******************************************************************************
[6711]4067 * VarUI2FromUI4 [OLEAUT32.268]
[4837]4068 */
4069HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* puiOut)
4070{
[6711]4071 TRACE("( %ld, %p ), stub\n", ulIn, puiOut );
[4837]4072
[9400]4073 if( ulIn > UI2_MAX )
[6711]4074 {
4075 return DISP_E_OVERFLOW;
4076 }
[4837]4077
[6711]4078 *puiOut = (USHORT) ulIn;
[4837]4079
[6711]4080 return S_OK;
[4837]4081}
4082
4083/******************************************************************************
[6711]4084 * VarUI4FromStr [OLEAUT32.277]
[4837]4085 */
4086HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG* pulOut)
4087{
[6711]4088 double dValue = 0.0;
4089 LPSTR pNewString = NULL;
[4837]4090
[6711]4091 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pulOut );
[4837]4092
[6711]4093 /* Check if we have a valid argument
4094 */
4095 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
4096 RemoveCharacterFromString( pNewString, "," );
4097 if( IsValidRealString( pNewString ) == FALSE )
4098 {
4099 return DISP_E_TYPEMISMATCH;
4100 }
[4837]4101
[6711]4102 /* Convert the valid string to a floating point number.
4103 */
4104 dValue = atof( pNewString );
[9400]4105
[6711]4106 /* We don't need the string anymore so free it.
4107 */
4108 HeapFree( GetProcessHeap(), 0, pNewString );
[4837]4109
[6711]4110 /* Check range of value.
[4837]4111 */
[21916]4112 dValue = rnd( dValue );
[6711]4113 if( dValue < UI4_MIN || dValue > UI4_MAX )
4114 {
4115 return DISP_E_OVERFLOW;
4116 }
[4837]4117
[6711]4118 *pulOut = (ULONG) dValue;
[4837]4119
[6711]4120 return S_OK;
[4837]4121}
4122
4123/**********************************************************************
4124 * VarUI2FromCy [OLEAUT32.263]
4125 * Convert currency to unsigned short
4126 */
4127HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut) {
[21916]4128 double t = rnd((((double)cyIn.DUMMYSTRUCTNAME_DOT Hi * 4294967296.0) + (double)cyIn.DUMMYSTRUCTNAME_DOT Lo) / 10000);
[9400]4129
[4837]4130 if (t > UI2_MAX || t < UI2_MIN) return DISP_E_OVERFLOW;
[9400]4131
[4837]4132 *pusOut = (USHORT)t;
[9400]4133
[4837]4134 return S_OK;
4135}
4136
4137/******************************************************************************
[6711]4138 * VarUI4FromUI1 [OLEAUT32.270]
[4837]4139 */
4140HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG* pulOut)
4141{
[6711]4142 TRACE("( %d, %p ), stub\n", bIn, pulOut );
[4837]4143
[6711]4144 *pulOut = (USHORT) bIn;
[4837]4145
[6711]4146 return S_OK;
[4837]4147}
4148
4149/******************************************************************************
[6711]4150 * VarUI4FromI2 [OLEAUT32.271]
[4837]4151 */
4152HRESULT WINAPI VarUI4FromI2(short uiIn, ULONG* pulOut)
4153{
[6711]4154 TRACE("( %d, %p ), stub\n", uiIn, pulOut );
[4837]4155
[6711]4156 if( uiIn < UI4_MIN )
4157 {
4158 return DISP_E_OVERFLOW;
4159 }
[4837]4160
[6711]4161 *pulOut = (ULONG) uiIn;
[4837]4162
[6711]4163 return S_OK;
[4837]4164}
4165
4166/******************************************************************************
[6711]4167 * VarUI4FromI4 [OLEAUT32.272]
[4837]4168 */
4169HRESULT WINAPI VarUI4FromI4(LONG lIn, ULONG* pulOut)
4170{
[6711]4171 TRACE("( %ld, %p ), stub\n", lIn, pulOut );
[4837]4172
[9400]4173 if( lIn < 0 )
[6711]4174 {
4175 return DISP_E_OVERFLOW;
4176 }
[4837]4177
[6711]4178 *pulOut = (ULONG) lIn;
[4837]4179
[6711]4180 return S_OK;
[4837]4181}
4182
4183/******************************************************************************
[6711]4184 * VarUI4FromR4 [OLEAUT32.273]
[4837]4185 */
4186HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG* pulOut)
4187{
[21916]4188 fltIn = rnd( fltIn );
[4837]4189 if( fltIn < UI4_MIN || fltIn > UI4_MAX )
[6711]4190 {
4191 return DISP_E_OVERFLOW;
4192 }
[4837]4193
[6711]4194 *pulOut = (ULONG) fltIn;
[4837]4195
[6711]4196 return S_OK;
[4837]4197}
4198
4199/******************************************************************************
[6711]4200 * VarUI4FromR8 [OLEAUT32.274]
[4837]4201 */
4202HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG* pulOut)
4203{
[6711]4204 TRACE("( %f, %p ), stub\n", dblIn, pulOut );
[4837]4205
[21916]4206 dblIn = rnd( dblIn );
[6711]4207 if( dblIn < UI4_MIN || dblIn > UI4_MAX )
4208 {
4209 return DISP_E_OVERFLOW;
[6944]4210 }
[4837]4211
[6711]4212 *pulOut = (ULONG) dblIn;
[4837]4213
[6711]4214 return S_OK;
[4837]4215}
4216
4217/******************************************************************************
[6711]4218 * VarUI4FromDate [OLEAUT32.275]
[4837]4219 */
4220HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG* pulOut)
4221{
[6711]4222 TRACE("( %f, %p ), stub\n", dateIn, pulOut );
[4837]4223
[21916]4224 dateIn = rnd( dateIn );
[6944]4225 if( dateIn < UI4_MIN || dateIn > UI4_MAX )
[6711]4226 {
4227 return DISP_E_OVERFLOW;
4228 }
[4837]4229
[6711]4230 *pulOut = (ULONG) dateIn;
[4837]4231
[6711]4232 return S_OK;
[4837]4233}
4234
4235/******************************************************************************
[6711]4236 * VarUI4FromBool [OLEAUT32.279]
[4837]4237 */
4238HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG* pulOut)
4239{
[6711]4240 TRACE("( %d, %p ), stub\n", boolIn, pulOut );
[4837]4241
[6711]4242 *pulOut = (ULONG) boolIn;
[4837]4243
[6711]4244 return S_OK;
[4837]4245}
4246
4247/******************************************************************************
[6711]4248 * VarUI4FromI1 [OLEAUT32.280]
[4837]4249 */
4250HRESULT WINAPI VarUI4FromI1(CHAR cIn, ULONG* pulOut)
4251{
[6711]4252 TRACE("( %c, %p ), stub\n", cIn, pulOut );
[4837]4253
[6711]4254 *pulOut = (ULONG) cIn;
[4837]4255
[6711]4256 return S_OK;
[4837]4257}
4258
4259/******************************************************************************
[6711]4260 * VarUI4FromUI2 [OLEAUT32.281]
[4837]4261 */
4262HRESULT WINAPI VarUI4FromUI2(USHORT uiIn, ULONG* pulOut)
4263{
[6711]4264 TRACE("( %d, %p ), stub\n", uiIn, pulOut );
[4837]4265
[6711]4266 *pulOut = (ULONG) uiIn;
[4837]4267
[6711]4268 return S_OK;
[4837]4269}
4270
4271/**********************************************************************
4272 * VarUI4FromCy [OLEAUT32.276]
4273 * Convert currency to unsigned long
4274 */
4275HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG* pulOut) {
[21916]4276 double t = rnd((((double)cyIn.DUMMYSTRUCTNAME_DOT Hi * 4294967296.0) + (double)cyIn.DUMMYSTRUCTNAME_DOT Lo) / 10000);
[9400]4277
[4837]4278 if (t > UI4_MAX || t < UI4_MIN) return DISP_E_OVERFLOW;
4279
4280 *pulOut = (ULONG)t;
4281
4282 return S_OK;
4283}
4284
4285/**********************************************************************
4286 * VarCyFromUI1 [OLEAUT32.98]
4287 * Convert unsigned char to currency
4288 */
4289HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pcyOut) {
[21916]4290 pcyOut->DUMMYSTRUCTNAME_DOT Hi = 0;
4291 pcyOut->DUMMYSTRUCTNAME_DOT Lo = ((ULONG)bIn) * 10000;
[6944]4292
4293 return S_OK;
[4837]4294}
4295
4296/**********************************************************************
4297 * VarCyFromI2 [OLEAUT32.99]
4298 * Convert signed short to currency
4299 */
4300HRESULT WINAPI VarCyFromI2(short sIn, CY* pcyOut) {
[21916]4301 if (sIn < 0) pcyOut->DUMMYSTRUCTNAME_DOT Hi = -1;
4302 else pcyOut->DUMMYSTRUCTNAME_DOT Hi = 0;
4303 pcyOut->DUMMYSTRUCTNAME_DOT Lo = ((ULONG)sIn) * 10000;
[6944]4304
4305 return S_OK;
[4837]4306}
4307
4308/**********************************************************************
4309 * VarCyFromI4 [OLEAUT32.100]
4310 * Convert signed long to currency
4311 */
4312HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pcyOut) {
4313 double t = (double)lIn * (double)10000;
[21916]4314 pcyOut->DUMMYSTRUCTNAME_DOT Hi = (LONG)(t / (double)4294967296.0);
4315 pcyOut->DUMMYSTRUCTNAME_DOT Lo = (ULONG)fmod(t, (double)4294967296.0);
4316 if (lIn < 0) pcyOut->DUMMYSTRUCTNAME_DOT Hi--;
[9400]4317
[4837]4318 return S_OK;
4319}
4320
4321/**********************************************************************
4322 * VarCyFromR4 [OLEAUT32.101]
4323 * Convert float to currency
4324 */
4325HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pcyOut) {
[21916]4326 double t = rnd((double)fltIn * (double)10000);
4327 pcyOut->DUMMYSTRUCTNAME_DOT Hi = (LONG)(t / (double)4294967296.0);
4328 pcyOut->DUMMYSTRUCTNAME_DOT Lo = (ULONG)fmod(t, (double)4294967296.0);
4329 if (fltIn < 0) pcyOut->DUMMYSTRUCTNAME_DOT Hi--;
[9400]4330
[4837]4331 return S_OK;
4332}
4333
4334/**********************************************************************
4335 * VarCyFromR8 [OLEAUT32.102]
4336 * Convert double to currency
4337 */
4338HRESULT WINAPI VarCyFromR8(double dblIn, CY* pcyOut) {
[21916]4339 double t = rnd(dblIn * (double)10000);
4340 pcyOut->DUMMYSTRUCTNAME_DOT Hi = (LONG)(t / (double)4294967296.0);
4341 pcyOut->DUMMYSTRUCTNAME_DOT Lo = (ULONG)fmod(t, (double)4294967296.0);
4342 if (dblIn < 0) pcyOut->DUMMYSTRUCTNAME_DOT Hi--;
[4837]4343
4344 return S_OK;
4345}
4346
4347/**********************************************************************
4348 * VarCyFromDate [OLEAUT32.103]
4349 * Convert date to currency
4350 */
4351HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pcyOut) {
[21916]4352 double t = rnd((double)dateIn * (double)10000);
4353 pcyOut->DUMMYSTRUCTNAME_DOT Hi = (LONG)(t / (double)4294967296.0);
4354 pcyOut->DUMMYSTRUCTNAME_DOT Lo = (ULONG)fmod(t, (double)4294967296.0);
4355 if (dateIn < 0) pcyOut->DUMMYSTRUCTNAME_DOT Hi--;
[4837]4356
4357 return S_OK;
4358}
4359
4360/**********************************************************************
4361 * VarCyFromStr [OLEAUT32.104]
[9400]4362 * FIXME: Never tested with decimal seperator other than '.'
[4837]4363 */
4364HRESULT WINAPI VarCyFromStr(OLECHAR *strIn, LCID lcid, ULONG dwFlags, CY *pcyOut) {
[9400]4365
4366 LPSTR pNewString = NULL;
4367 char *decSep = NULL;
4368 char *strPtr,*curPtr = NULL;
4369 int size, rc;
4370 double currencyVal = 0.0;
4371
4372
4373 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
4374 TRACE("( '%s', 0x%08lx, 0x%08lx, %p )\n", pNewString, lcid, dwFlags, pcyOut );
4375
4376 /* Get locale information - Decimal Seperator (size includes 0x00) */
4377 size = GetLocaleInfoA(lcid, LOCALE_SDECIMAL, NULL, 0);
4378 decSep = (char *) malloc(size);
4379 rc = GetLocaleInfoA(lcid, LOCALE_SDECIMAL, decSep, size);
4380 TRACE("Decimal Seperator is '%s'\n", decSep);
4381
4382 /* Now copy to temporary buffer, skipping any character except 0-9 and
4383 the decimal seperator */
4384 curPtr = pBuffer; /* Current position in string being built */
4385 strPtr = pNewString; /* Current position in supplied currenct string */
4386
4387 while (*strPtr) {
4388 /* If decimal seperator, skip it and put '.' in string */
4389 if (strncmp(strPtr, decSep, (size-1)) == 0) {
4390 strPtr = strPtr + (size-1);
4391 *curPtr = '.';
4392 curPtr++;
4393 } else if ((*strPtr == '+' || *strPtr == '-') ||
4394 (*strPtr >= '0' && *strPtr <= '9')) {
4395 *curPtr = *strPtr;
4396 strPtr++;
4397 curPtr++;
4398 } else strPtr++;
4399 }
4400 *curPtr = 0x00;
4401
4402 /* Try to get currency into a double */
4403 currencyVal = atof(pBuffer);
4404 TRACE("Converted string '%s' to %f\n", pBuffer, currencyVal);
4405
4406 /* Free allocated storage */
4407 HeapFree( GetProcessHeap(), 0, pNewString );
4408 free(decSep);
4409
4410 /* Convert double -> currency using internal routine */
4411 return VarCyFromR8(currencyVal, pcyOut);
[4837]4412}
4413
[9400]4414
[4837]4415/**********************************************************************
4416 * VarCyFromBool [OLEAUT32.106]
4417 * Convert boolean to currency
4418 */
4419HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pcyOut) {
[21916]4420 if (boolIn < 0) pcyOut->DUMMYSTRUCTNAME_DOT Hi = -1;
4421 else pcyOut->DUMMYSTRUCTNAME_DOT Hi = 0;
4422 pcyOut->DUMMYSTRUCTNAME_DOT Lo = (ULONG)boolIn * (ULONG)10000;
[9400]4423
[4837]4424 return S_OK;
4425}
4426
4427/**********************************************************************
4428 * VarCyFromI1 [OLEAUT32.225]
4429 * Convert signed char to currency
4430 */
[6575]4431HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pcyOut) {
[21916]4432 if (cIn < 0) pcyOut->DUMMYSTRUCTNAME_DOT Hi = -1;
4433 else pcyOut->DUMMYSTRUCTNAME_DOT Hi = 0;
4434 pcyOut->DUMMYSTRUCTNAME_DOT Lo = (ULONG)cIn * (ULONG)10000;
[9400]4435
[4837]4436 return S_OK;
4437}
4438
4439/**********************************************************************
4440 * VarCyFromUI2 [OLEAUT32.226]
4441 * Convert unsigned short to currency
4442 */
4443HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pcyOut) {
[21916]4444 pcyOut->DUMMYSTRUCTNAME_DOT Hi = 0;
4445 pcyOut->DUMMYSTRUCTNAME_DOT Lo = (ULONG)usIn * (ULONG)10000;
[9400]4446
[4837]4447 return S_OK;
4448}
4449
4450/**********************************************************************
4451 * VarCyFromUI4 [OLEAUT32.227]
4452 * Convert unsigned long to currency
4453 */
4454HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pcyOut) {
4455 double t = (double)ulIn * (double)10000;
[21916]4456 pcyOut->DUMMYSTRUCTNAME_DOT Hi = (LONG)(t / (double)4294967296.0);
4457 pcyOut->DUMMYSTRUCTNAME_DOT Lo = (ULONG)fmod(t, (double)4294967296.0);
[9400]4458
[4837]4459 return S_OK;
4460}
4461
4462
4463/**********************************************************************
4464 * DosDateTimeToVariantTime [OLEAUT32.14]
4465 * Convert dos representation of time to the date and time representation
4466 * stored in a variant.
4467 */
4468INT WINAPI DosDateTimeToVariantTime(USHORT wDosDate, USHORT wDosTime,
4469 DATE *pvtime)
4470{
4471 struct tm t;
4472
[7916]4473 TRACE("( 0x%x, 0x%x, %p ), stub\n", wDosDate, wDosTime, pvtime );
[9400]4474
[4837]4475 t.tm_sec = (wDosTime & 0x001f) * 2;
4476 t.tm_min = (wDosTime & 0x07e0) >> 5;
4477 t.tm_hour = (wDosTime & 0xf800) >> 11;
[9400]4478
[4837]4479 t.tm_mday = (wDosDate & 0x001f);
4480 t.tm_mon = (wDosDate & 0x01e0) >> 5;
4481 t.tm_year = ((wDosDate & 0xfe00) >> 9) + 1980;
4482
4483 return TmToDATE( &t, pvtime );
4484}
4485
[6575]4486
4487/**********************************************************************
4488 * VarParseNumFromStr [OLEAUT32.46]
4489 */
4490HRESULT WINAPI VarParseNumFromStr(OLECHAR * strIn, LCID lcid, ULONG dwFlags,
4491 NUMPARSE * pnumprs, BYTE * rgbDig)
4492{
4493 int i,lastent=0;
4494 int cDig;
[9400]4495 BOOL foundNum=FALSE;
4496
[6575]4497 FIXME("(%s,flags=%lx,....), partial stub!\n",debugstr_w(strIn),dwFlags);
4498 FIXME("numparse: cDig=%d, InFlags=%lx\n",pnumprs->cDig,pnumprs->dwInFlags);
4499
4500 /* The other struct components are to be set by us */
4501 memset(rgbDig,0,pnumprs->cDig);
4502
[9400]4503 /* FIXME: Just patching some values in */
4504 pnumprs->nPwr10 = 0;
4505 pnumprs->nBaseShift = 0;
4506 pnumprs->cchUsed = lastent;
4507 pnumprs->dwOutFlags = NUMPRS_DECIMAL;
4508
[6575]4509 cDig = 0;
4510 for (i=0; strIn[i] ;i++) {
[6711]4511 if ((strIn[i]>='0') && (strIn[i]<='9')) {
[9400]4512 foundNum = TRUE;
[6711]4513 if (pnumprs->cDig > cDig) {
4514 *(rgbDig++)=strIn[i]-'0';
4515 cDig++;
4516 lastent = i;
4517 }
[9400]4518 } else if ((strIn[i]=='-') && (foundNum==FALSE)) {
4519 pnumprs->dwOutFlags |= NUMPRS_NEG;
4520 }
[6575]4521 }
[6711]4522 pnumprs->cDig = cDig;
[9400]4523 TRACE("numparse out: cDig=%d, OutFlags=%lx\n",pnumprs->cDig,pnumprs->dwOutFlags);
[6575]4524 return S_OK;
4525}
4526
4527
4528/**********************************************************************
4529 * VarNumFromParseNum [OLEAUT32.47]
4530 */
4531HRESULT WINAPI VarNumFromParseNum(NUMPARSE * pnumprs, BYTE * rgbDig,
4532 ULONG dwVtBits, VARIANT * pvar)
4533{
4534 DWORD xint;
4535 int i;
[21308]4536 FIXME("(..,dwVtBits=%lx,....), partial stub!\n",dwVtBits);
[6575]4537
4538 xint = 0;
4539 for (i=0;i<pnumprs->cDig;i++)
[21308]4540 xint = xint*10 + rgbDig[i];
[6575]4541
[9400]4542 if (pnumprs->dwOutFlags & NUMPRS_NEG) {
4543 xint = xint * -1;
4544 }
4545
[6575]4546 VariantInit(pvar);
4547 if (dwVtBits & VTBIT_I4) {
[6711]4548 V_VT(pvar) = VT_I4;
4549 V_UNION(pvar,intVal) = xint;
4550 return S_OK;
[6575]4551 }
4552 if (dwVtBits & VTBIT_R8) {
[6711]4553 V_VT(pvar) = VT_R8;
4554 V_UNION(pvar,dblVal) = xint;
4555 return S_OK;
[9400]4556 }
4557 if (dwVtBits & VTBIT_R4) {
4558 V_VT(pvar) = VT_R4;
4559 V_UNION(pvar,fltVal) = xint;
4560 return S_OK;
4561 }
4562 if (dwVtBits & VTBIT_I2) {
4563 V_VT(pvar) = VT_I2;
4564 V_UNION(pvar,iVal) = xint;
4565 return S_OK;
4566 }
4567 /* FIXME: Currency should be from a double */
4568 if (dwVtBits & VTBIT_CY) {
4569 V_VT(pvar) = VT_CY;
4570 TRACE("Calculated currency is xint=%ld\n", xint);
4571 VarCyFromInt( (int) xint, &V_UNION(pvar,cyVal) );
[21916]4572 TRACE("Calculated cy is %ld,%lu\n", V_UNION(pvar,cyVal).DUMMYSTRUCTNAME_DOT Hi, V_UNION(pvar,cyVal).DUMMYSTRUCTNAME_DOT Lo);
[9400]4573 return VarCyFromInt( (int) xint, &V_UNION(pvar,cyVal) );
4574 }
4575
4576 FIXME("vtbitmask is unsupported %lx, int=%d\n",dwVtBits, (int) xint);
[6711]4577 return E_FAIL;
[21308]4578}
[10629]4579
4580
[6575]4581/**********************************************************************
[9400]4582 * VarFormatDateTime [OLEAUT32.97]
4583 */
4584HRESULT WINAPI VarFormatDateTime(LPVARIANT var, INT format, ULONG dwFlags, BSTR *out)
4585{
4586 FIXME("%p %d %lx %p\n", var, format, dwFlags, out);
4587 return E_NOTIMPL;
4588}
4589
4590/**********************************************************************
4591 * VarFormatCurrency [OLEAUT32.127]
4592 */
4593HRESULT WINAPI VarFormatCurrency(LPVARIANT var, INT digits, INT lead, INT paren, INT group, ULONG dwFlags, BSTR *out)
4594{
4595 FIXME("%p %d %d %d %d %lx %p\n", var, digits, lead, paren, group, dwFlags, out);
4596 return E_NOTIMPL;
4597}
4598
4599/**********************************************************************
[6944]4600 * VariantTimeToDosDateTime [OLEAUT32.13]
[6575]4601 * Convert variant representation of time to the date and time representation
4602 * stored in dos.
4603 */
4604INT WINAPI VariantTimeToDosDateTime(DATE pvtime, USHORT *wDosDate, USHORT *wDosTime)
4605{
[7916]4606 struct tm t;
[7351]4607 *wDosTime = 0;
4608 *wDosDate = 0;
[6575]4609
[7916]4610 TRACE("( 0x%x, 0x%x, %p ), stub\n", *wDosDate, *wDosTime, &pvtime );
[6575]4611
4612 if (DateToTm(pvtime, 0, &t) < 0) return 0;
4613
4614 *wDosTime = *wDosTime | (t.tm_sec / 2);
4615 *wDosTime = *wDosTime | (t.tm_min << 5);
4616 *wDosTime = *wDosTime | (t.tm_hour << 11);
4617
4618 *wDosDate = *wDosDate | t.tm_mday ;
4619 *wDosDate = *wDosDate | t.tm_mon << 5;
4620 *wDosDate = *wDosDate | ((t.tm_year - 1980) << 9) ;
4621
4622 return 1;
4623}
4624
4625
[6944]4626/***********************************************************************
4627 * SystemTimeToVariantTime [OLEAUT32.184]
4628 */
[6575]4629HRESULT WINAPI SystemTimeToVariantTime( LPSYSTEMTIME lpSystemTime, double *pvtime )
4630{
4631 struct tm t;
4632
4633 TRACE(" %d/%d/%d %d:%d:%d\n",
4634 lpSystemTime->wMonth, lpSystemTime->wDay,
4635 lpSystemTime->wYear, lpSystemTime->wHour,
4636 lpSystemTime->wMinute, lpSystemTime->wSecond);
4637
4638 if (lpSystemTime->wYear >= 1900)
4639 {
4640 t.tm_sec = lpSystemTime->wSecond;
4641 t.tm_min = lpSystemTime->wMinute;
4642 t.tm_hour = lpSystemTime->wHour;
4643
4644 t.tm_mday = lpSystemTime->wDay;
[9400]4645 t.tm_mon = lpSystemTime->wMonth - 1; /* tm_mon is 0..11, wMonth is 1..12 */
[6575]4646 t.tm_year = lpSystemTime->wYear;
4647
4648 return TmToDATE( &t, pvtime );
4649 }
4650 else
4651 {
[9400]4652 double tmpDate;
4653 long firstDayOfNextYear;
4654 long thisDay;
4655 long leftInYear;
4656 long result;
4657
4658 double decimalPart = 0.0;
4659
[6575]4660 t.tm_sec = lpSystemTime->wSecond;
4661 t.tm_min = lpSystemTime->wMinute;
4662 t.tm_hour = lpSystemTime->wHour;
4663
[9400]4664 /* Step year forward the same number of years before 1900 */
[6575]4665 t.tm_year = 1900 + 1899 - lpSystemTime->wYear;
[9400]4666 t.tm_mon = lpSystemTime->wMonth - 1;
4667 t.tm_mday = lpSystemTime->wDay;
[6575]4668
[9400]4669 /* Calculate date */
[6575]4670 TmToDATE( &t, pvtime );
4671
[9400]4672 thisDay = (double) floor( *pvtime );
4673 decimalPart = fmod( *pvtime, thisDay );
[6575]4674
[9400]4675 /* Now, calculate the same time for the first of Jan that year */
4676 t.tm_mon = 0;
4677 t.tm_mday = 1;
4678 t.tm_sec = 0;
4679 t.tm_min = 0;
4680 t.tm_hour = 0;
4681 t.tm_year = t.tm_year+1;
4682 TmToDATE( &t, &tmpDate );
4683 firstDayOfNextYear = (long) floor(tmpDate);
4684
4685 /* Finally since we know the size of the year, subtract the two to get
4686 remaining time in the year */
4687 leftInYear = firstDayOfNextYear - thisDay;
4688
4689 /* Now we want full years up to the year in question, and remainder of year
4690 of the year in question */
4691 if (isleap(lpSystemTime->wYear) ) {
4692 TRACE("Extra day due to leap year\n");
4693 result = 2.0 - ((firstDayOfNextYear - 366) + leftInYear - 2.0);
4694 } else {
4695 result = 2.0 - ((firstDayOfNextYear - 365) + leftInYear - 2.0);
4696 }
4697 *pvtime = (double) result + decimalPart;
4698 TRACE("<1899 support: returned %f, 1st day %ld, thisday %ld, left %ld\n", *pvtime, firstDayOfNextYear, thisDay, leftInYear);
4699
[6575]4700 return 1;
4701 }
4702
4703 return 0;
4704}
4705
[6944]4706/***********************************************************************
4707 * VariantTimeToSystemTime [OLEAUT32.185]
4708 */
[6575]4709HRESULT WINAPI VariantTimeToSystemTime( double vtime, LPSYSTEMTIME lpSystemTime )
4710{
4711 double t = 0, timeofday = 0;
4712
4713 static const BYTE Days_Per_Month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4714 static const BYTE Days_Per_Month_LY[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4715
4716 /* The Month_Code is used to find the Day of the Week (LY = LeapYear)*/
4717 static const BYTE Month_Code[] = {0, 1, 4, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6};
4718 static const BYTE Month_Code_LY[] = {0, 0, 3, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6};
4719
4720 /* The Century_Code is used to find the Day of the Week */
4721 static const BYTE Century_Code[] = {0, 6, 4, 2};
4722
4723 struct tm r;
4724
[9400]4725 TRACE(" Variant = %f SYSTEMTIME ptr %p\n", vtime, lpSystemTime);
[6575]4726
4727 if (vtime >= 0)
4728 {
4729
4730 if (DateToTm(vtime, 0, &r ) <= 0) return 0;
4731
4732 lpSystemTime->wSecond = r.tm_sec;
4733 lpSystemTime->wMinute = r.tm_min;
4734 lpSystemTime->wHour = r.tm_hour;
4735 lpSystemTime->wDay = r.tm_mday;
4736 lpSystemTime->wMonth = r.tm_mon;
4737
4738 if (lpSystemTime->wMonth == 12)
4739 lpSystemTime->wMonth = 1;
4740 else
4741 lpSystemTime->wMonth++;
4742
4743 lpSystemTime->wYear = r.tm_year;
4744 }
4745 else
4746 {
4747 vtime = -1*vtime;
4748
4749 if (DateToTm(vtime, 0, &r ) <= 0) return 0;
4750
4751 lpSystemTime->wSecond = r.tm_sec;
4752 lpSystemTime->wMinute = r.tm_min;
4753 lpSystemTime->wHour = r.tm_hour;
4754
4755 lpSystemTime->wMonth = 13 - r.tm_mon;
4756
4757 if (lpSystemTime->wMonth == 1)
4758 lpSystemTime->wMonth = 12;
4759 else
4760 lpSystemTime->wMonth--;
4761
4762 lpSystemTime->wYear = 1899 - (r.tm_year - 1900);
4763
4764 if (!isleap(lpSystemTime->wYear) )
4765 lpSystemTime->wDay = Days_Per_Month[13 - lpSystemTime->wMonth] - r.tm_mday;
4766 else
4767 lpSystemTime->wDay = Days_Per_Month_LY[13 - lpSystemTime->wMonth] - r.tm_mday;
4768
4769
4770 }
4771
4772 if (!isleap(lpSystemTime->wYear))
4773 {
4774 /*
4775 (Century_Code+Month_Code+Year_Code+Day) % 7
4776
4777 The century code repeats every 400 years , so the array
4778 works out like this,
4779
4780 Century_Code[0] is for 16th/20th Centry
4781 Century_Code[1] is for 17th/21th Centry
4782 Century_Code[2] is for 18th/22th Centry
4783 Century_Code[3] is for 19th/23th Centry
4784
4785 The year code is found with the formula (year + (year / 4))
4786 the "year" must be between 0 and 99 .
4787
4788 The Month Code (Month_Code[1]) starts with January and
4789 ends with December.
4790 */
4791
4792 lpSystemTime->wDayOfWeek = (
4793 Century_Code[(( (lpSystemTime->wYear+100) - lpSystemTime->wYear%100) /100) %4]+
4794 ((lpSystemTime->wYear%100)+(lpSystemTime->wYear%100)/4)+
4795 Month_Code[lpSystemTime->wMonth]+
4796 lpSystemTime->wDay) % 7;
4797
4798 if (lpSystemTime->wDayOfWeek == 0) lpSystemTime->wDayOfWeek = 7;
4799 else lpSystemTime->wDayOfWeek -= 1;
4800 }
4801 else
4802 {
4803 lpSystemTime->wDayOfWeek = (
4804 Century_Code[(((lpSystemTime->wYear+100) - lpSystemTime->wYear%100)/100)%4]+
4805 ((lpSystemTime->wYear%100)+(lpSystemTime->wYear%100)/4)+
4806 Month_Code_LY[lpSystemTime->wMonth]+
4807 lpSystemTime->wDay) % 7;
4808
4809 if (lpSystemTime->wDayOfWeek == 0) lpSystemTime->wDayOfWeek = 7;
4810 else lpSystemTime->wDayOfWeek -= 1;
4811 }
4812
4813 t = floor(vtime);
4814 timeofday = vtime - t;
4815
4816 lpSystemTime->wMilliseconds = (timeofday
4817 - lpSystemTime->wHour*(1/24)
4818 - lpSystemTime->wMinute*(1/1440)
4819 - lpSystemTime->wSecond*(1/86400) )*(1/5184000);
4820
4821 return 1;
4822}
4823
[6944]4824/***********************************************************************
4825 * VarUdateFromDate [OLEAUT32.331]
4826 */
[6575]4827HRESULT WINAPI VarUdateFromDate( DATE datein, ULONG dwFlags, UDATE *pudateout)
4828{
4829 HRESULT i = 0;
4830 static const BYTE Days_Per_Month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4831 static const BYTE Days_Per_Month_LY[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4832
4833 TRACE("DATE = %f\n", (double)datein);
4834 i = VariantTimeToSystemTime(datein, &(pudateout->st) );
4835
4836 if (i)
4837 {
4838 pudateout->wDayOfYear = 0;
4839
4840 if (isleap(pudateout->st.wYear))
4841 {
4842 for (i =1; i<pudateout->st.wMonth; i++)
4843 pudateout->wDayOfYear += Days_Per_Month[i];
4844 }
4845 else
4846 {
4847 for (i =1; i<pudateout->st.wMonth; i++)
4848 pudateout->wDayOfYear += Days_Per_Month_LY[i];
4849 }
4850
4851 pudateout->wDayOfYear += pudateout->st.wDay;
4852 dwFlags = 0; /*VAR_VALIDDATE*/
4853 }
4854 else dwFlags = 0;
4855
4856 return i;
4857}
4858
[6944]4859/***********************************************************************
4860 * VarDateFromUdate [OLEAUT32.330]
4861 */
[6575]4862HRESULT WINAPI VarDateFromUdate(UDATE *pudateout,
4863 ULONG dwFlags, DATE *datein)
4864{
4865 HRESULT i;
4866 double t = 0;
4867 TRACE(" %d/%d/%d %d:%d:%d\n",
4868 pudateout->st.wMonth, pudateout->st.wDay,
4869 pudateout->st.wYear, pudateout->st.wHour,
4870 pudateout->st.wMinute, pudateout->st.wSecond);
4871
4872
4873 i = SystemTimeToVariantTime(&(pudateout->st), &t);
4874 *datein = t;
4875
[9400]4876 if (i) return S_OK;
4877 else return E_INVALIDARG;
[6575]4878}
4879
4880
4881/**********************************************************************
[9400]4882 * VarBstrCmp [OLEAUT32.314]
[6575]4883 *
[9400]4884 * flags can be:
[6575]4885 * NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS
4886 * NORM_IGNORESTRINGWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA
4887 *
4888 */
4889HRESULT WINAPI VarBstrCmp(BSTR left, BSTR right, LCID lcid, DWORD flags)
4890{
[9400]4891 INT r;
[6575]4892
[9400]4893 TRACE("( %s %s %ld %lx ) partial stub\n", debugstr_w(left), debugstr_w(right), lcid, flags);
[6575]4894
[9400]4895 /* Contrary to the MSDN, this returns eq for null vs null, null vs L"" and L"" vs NULL */
4896 if((!left) || (!right)) {
[6575]4897
[9400]4898 if (!left && (!right || *right==0)) return VARCMP_EQ;
4899 else if (!right && (!left || *left==0)) return VARCMP_EQ;
4900 else return VARCMP_NULL;
4901 }
4902
[6575]4903 if(flags&NORM_IGNORECASE)
4904 r = lstrcmpiW(left,right);
4905 else
4906 r = lstrcmpW(left,right);
4907
4908 if(r<0)
4909 return VARCMP_LT;
4910 if(r>0)
4911 return VARCMP_GT;
4912
4913 return VARCMP_EQ;
4914}
4915
4916/**********************************************************************
[9400]4917 * VarBstrCat [OLEAUT32.313]
[6575]4918 */
4919HRESULT WINAPI VarBstrCat(BSTR left, BSTR right, BSTR *out)
4920{
4921 BSTR result;
[9400]4922 int size = 0;
[6575]4923
4924 TRACE("( %s %s %p )\n", debugstr_w(left), debugstr_w(right), out);
4925
[9400]4926 /* On Windows, NULL parms are still handled (as empty strings) */
4927 if (left) size=size + lstrlenW(left);
4928 if (right) size=size + lstrlenW(right);
[6575]4929
[9400]4930 if (out) {
4931 result = SysAllocStringLen(NULL, size);
4932 *out = result;
4933 if (left) lstrcatW(result,left);
4934 if (right) lstrcatW(result,right);
4935 TRACE("result = %s, [%p]\n", debugstr_w(result), result);
4936 }
4937 return S_OK;
[6575]4938}
4939
[7916]4940/**********************************************************************
[9400]4941 * VarCat [OLEAUT32.318]
[7916]4942 */
4943HRESULT WINAPI VarCat(LPVARIANT left, LPVARIANT right, LPVARIANT out)
4944{
4945 /* Should we VariantClear out? */
4946 /* Can we handle array, vector, by ref etc. */
4947 if ((V_VT(left)&VT_TYPEMASK) == VT_NULL &&
4948 (V_VT(right)&VT_TYPEMASK) == VT_NULL)
4949 {
4950 V_VT(out) = VT_NULL;
4951 return S_OK;
4952 }
4953 else if (V_VT(left) == VT_BSTR && V_VT(right) == VT_BSTR)
4954 {
4955 V_VT(out) = VT_BSTR;
4956 VarBstrCat (V_BSTR(left), V_BSTR(right), &V_BSTR(out));
4957 return S_OK;
4958 }
4959 else
4960 FIXME ("types not supported\n");
4961 return S_OK;
4962}
[9400]4963
4964/**********************************************************************
4965 * VarCmp [OLEAUT32.176]
4966 *
4967 * flags can be:
4968 * NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS
4969 * NORM_IGNOREWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA
4970 *
4971 */
4972HRESULT WINAPI VarCmp(LPVARIANT left, LPVARIANT right, LCID lcid, DWORD flags)
4973{
4974
4975
4976 BOOL lOk = TRUE;
4977 BOOL rOk = TRUE;
4978 LONGLONG lVal = -1;
4979 LONGLONG rVal = -1;
4980
4981 TRACE("Left Var:\n");
4982 dump_Variant(left);
4983 TRACE("Right Var:\n");
4984 dump_Variant(right);
4985
4986 /* If either are null, then return VARCMP_NULL */
4987 if ((V_VT(left)&VT_TYPEMASK) == VT_NULL ||
4988 (V_VT(right)&VT_TYPEMASK) == VT_NULL)
4989 return VARCMP_NULL;
4990
4991 /* Strings - use VarBstrCmp */
4992 if ((V_VT(left)&VT_TYPEMASK) == VT_BSTR &&
4993 (V_VT(right)&VT_TYPEMASK) == VT_BSTR) {
4994 return VarBstrCmp(V_BSTR(left), V_BSTR(right), lcid, flags);
4995 }
4996
4997 /* Integers - Ideally like to use VarDecCmp, but no Dec support yet
4998 Use LONGLONG to maximize ranges */
4999 lOk = TRUE;
5000 switch (V_VT(left)&VT_TYPEMASK) {
5001 case VT_I1 : lVal = V_UNION(left,cVal); break;
5002 case VT_I2 : lVal = V_UNION(left,iVal); break;
5003 case VT_I4 : lVal = V_UNION(left,lVal); break;
5004 case VT_INT : lVal = V_UNION(left,lVal); break;
5005 case VT_UI1 : lVal = V_UNION(left,bVal); break;
5006 case VT_UI2 : lVal = V_UNION(left,uiVal); break;
5007 case VT_UI4 : lVal = V_UNION(left,ulVal); break;
5008 case VT_UINT : lVal = V_UNION(left,ulVal); break;
5009 default: lOk = FALSE;
5010 }
5011
5012 rOk = TRUE;
5013 switch (V_VT(right)&VT_TYPEMASK) {
5014 case VT_I1 : rVal = V_UNION(right,cVal); break;
5015 case VT_I2 : rVal = V_UNION(right,iVal); break;
5016 case VT_I4 : rVal = V_UNION(right,lVal); break;
5017 case VT_INT : rVal = V_UNION(right,lVal); break;
5018 case VT_UI1 : rVal = V_UNION(right,bVal); break;
5019 case VT_UI2 : rVal = V_UNION(right,uiVal); break;
5020 case VT_UI4 : rVal = V_UNION(right,ulVal); break;
5021 case VT_UINT : rVal = V_UNION(right,ulVal); break;
5022 default: rOk = FALSE;
5023 }
5024
5025 if (lOk && rOk) {
5026 if (lVal < rVal) {
5027 return VARCMP_LT;
5028 } else if (lVal > rVal) {
5029 return VARCMP_GT;
5030 } else {
5031 return VARCMP_EQ;
5032 }
5033 }
5034
5035 /* Strings - use VarBstrCmp */
5036 if ((V_VT(left)&VT_TYPEMASK) == VT_DATE &&
5037 (V_VT(right)&VT_TYPEMASK) == VT_DATE) {
5038
5039 if (floor(V_UNION(left,date)) == floor(V_UNION(right,date))) {
5040 /* Due to floating point rounding errors, calculate varDate in whole numbers) */
5041 double wholePart = 0.0;
5042 double leftR;
5043 double rightR;
5044
5045 /* Get the fraction * 24*60*60 to make it into whole seconds */
5046 wholePart = (double) floor( V_UNION(left,date) );
5047 if (wholePart == 0) wholePart = 1;
5048 leftR = floor(fmod( V_UNION(left,date), wholePart ) * (24*60*60));
5049
5050 wholePart = (double) floor( V_UNION(right,date) );
5051 if (wholePart == 0) wholePart = 1;
5052 rightR = floor(fmod( V_UNION(right,date), wholePart ) * (24*60*60));
5053
5054 if (leftR < rightR) {
5055 return VARCMP_LT;
5056 } else if (leftR > rightR) {
5057 return VARCMP_GT;
5058 } else {
5059 return VARCMP_EQ;
5060 }
5061
5062 } else if (V_UNION(left,date) < V_UNION(right,date)) {
5063 return VARCMP_LT;
5064 } else if (V_UNION(left,date) > V_UNION(right,date)) {
5065 return VARCMP_GT;
5066 }
5067 }
5068
5069
5070 FIXME("VarCmp partial implementation, doesnt support these pair of variant types");
5071 return E_FAIL;
5072}
5073
5074/**********************************************************************
5075 * VarAnd [OLEAUT32.142]
5076 *
5077 */
5078HRESULT WINAPI VarAnd(LPVARIANT left, LPVARIANT right, LPVARIANT result)
5079{
5080 HRESULT rc = E_FAIL;
5081
5082
5083 TRACE("Left Var:\n");
5084 dump_Variant(left);
5085 TRACE("Right Var:\n");
5086 dump_Variant(right);
5087
5088 if ((V_VT(left)&VT_TYPEMASK) == VT_BOOL &&
5089 (V_VT(right)&VT_TYPEMASK) == VT_BOOL) {
5090
5091 V_VT(result) = VT_BOOL;
5092 if (V_BOOL(left) && V_BOOL(right)) {
5093 V_BOOL(result) = VARIANT_TRUE;
5094 } else {
5095 V_BOOL(result) = VARIANT_FALSE;
5096 }
5097 rc = S_OK;
5098
5099 } else {
5100 FIXME("VarAnd stub\n");
5101 }
5102
5103 TRACE("rc=%d, Result:\n", (int) rc);
5104 dump_Variant(result);
5105 return rc;
5106}
5107
5108/**********************************************************************
5109 * VarNot [OLEAUT32.174]
5110 *
5111 */
5112HRESULT WINAPI VarNot(LPVARIANT in, LPVARIANT result)
5113{
5114 HRESULT rc = E_FAIL;
5115
5116 TRACE("Var In:\n");
5117 dump_Variant(in);
5118
5119 if ((V_VT(in)&VT_TYPEMASK) == VT_BOOL) {
5120
5121 V_VT(result) = VT_BOOL;
5122 if (V_BOOL(in)) {
5123 V_BOOL(result) = VARIANT_FALSE;
5124 } else {
5125 V_BOOL(result) = VARIANT_TRUE;
5126 }
5127 rc = S_OK;
5128
5129 } else {
5130 FIXME("VarNot stub\n");
5131 }
5132
5133 TRACE("rc=%d, Result:\n", (int) rc);
5134 dump_Variant(result);
5135 return rc;
5136}
5137
5138/**********************************************************************
5139 * VarTokenizeFormatString [OLEAUT32.140]
5140 *
5141 * From investigation on W2K, a list is built up which is:
5142 *
5143 * <0x00> AA BB - Copy from AA for BB chars (Note 1 byte with wrap!)
5144 * <token> - Insert appropriate token
5145 *
5146 */
5147HRESULT WINAPI VarTokenizeFormatString(LPOLESTR format, LPBYTE rgbTok,
5148 int cbTok, int iFirstDay, int iFirstWeek,
5149 LCID lcid, int *pcbActual) {
5150
5151 FORMATHDR *hdr;
5152 int realLen, formatLeft;
5153 BYTE *pData;
5154 LPSTR pFormatA, pStart;
5155 int checkStr;
5156 BOOL insertCopy = FALSE;
5157 LPSTR copyFrom = NULL;
5158
5159 TRACE("'%s', %p %d %d %d only date support\n", debugstr_w(format), rgbTok, cbTok,
5160 iFirstDay, iFirstWeek);
5161
5162 /* Big enough for header? */
5163 if (cbTok < sizeof(FORMATHDR)) {
5164 return TYPE_E_BUFFERTOOSMALL;
5165 }
5166
5167 /* Insert header */
5168 hdr = (FORMATHDR *) rgbTok;
5169 memset(hdr, 0x00, sizeof(FORMATHDR));
5170 hdr->hex3 = 0x03; /* No idea what these are */
5171 hdr->hex6 = 0x06;
5172
5173 /* Start parsing string */
5174 realLen = sizeof(FORMATHDR);
5175 pData = rgbTok + realLen;
5176 pFormatA = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
5177 pStart = pFormatA;
5178 formatLeft = strlen(pFormatA);
5179
5180 /* Work through the format */
5181 while (*pFormatA != 0x00) {
5182
5183 checkStr = 0;
5184 while (checkStr>=0 && (formatTokens[checkStr].tokenSize != 0x00)) {
5185 if (formatLeft >= formatTokens[checkStr].tokenSize &&
5186 strncmp(formatTokens[checkStr].str, pFormatA,
5187 formatTokens[checkStr].tokenSize) == 0) {
5188 TRACE("match on '%s'\n", formatTokens[checkStr].str);
5189
5190 /* Found Match! */
5191
5192 /* If we have skipped chars, insert the copy */
5193 if (insertCopy == TRUE) {
5194
5195 if ((realLen + 3) > cbTok) {
5196 HeapFree( GetProcessHeap(), 0, pFormatA );
5197 return TYPE_E_BUFFERTOOSMALL;
5198 }
5199 insertCopy = FALSE;
5200 *pData = TOK_COPY;
5201 pData++;
5202 *pData = (BYTE)(copyFrom - pStart);
5203 pData++;
5204 *pData = (BYTE)(pFormatA - copyFrom);
5205 pData++;
5206 realLen = realLen + 3;
5207 }
5208
5209
5210 /* Now insert the token itself */
5211 if ((realLen + 1) > cbTok) {
5212 HeapFree( GetProcessHeap(), 0, pFormatA );
5213 return TYPE_E_BUFFERTOOSMALL;
5214 }
5215 *pData = formatTokens[checkStr].tokenId;
5216 pData = pData + 1;
5217 realLen = realLen + 1;
5218
5219 pFormatA = pFormatA + formatTokens[checkStr].tokenSize;
5220 formatLeft = formatLeft - formatTokens[checkStr].tokenSize;
5221 checkStr = -1; /* Flag as found and break out of while loop */
5222 } else {
5223 checkStr++;
5224 }
5225 }
5226
5227 /* Did we ever match a token? */
5228 if (checkStr != -1 && insertCopy == FALSE) {
5229 TRACE("No match - need to insert copy from %p [%p]\n", pFormatA, pStart);
5230 insertCopy = TRUE;
5231 copyFrom = pFormatA;
5232 } else if (checkStr != -1) {
5233 pFormatA = pFormatA + 1;
5234 }
5235
5236 }
5237
5238 /* Finally, if we have skipped chars, insert the copy */
5239 if (insertCopy == TRUE) {
5240
5241 TRACE("Chars left over, so still copy %p,%p,%p\n", copyFrom, pStart, pFormatA);
5242 if ((realLen + 3) > cbTok) {
5243 HeapFree( GetProcessHeap(), 0, pFormatA );
5244 return TYPE_E_BUFFERTOOSMALL;
5245 }
5246 insertCopy = FALSE;
5247 *pData = TOK_COPY;
5248 pData++;
5249 *pData = (BYTE)(copyFrom - pStart);
5250 pData++;
5251 *pData = (BYTE)(pFormatA - copyFrom);
5252 pData++;
5253 realLen = realLen + 3;
5254 }
5255
5256 /* Finally insert the terminator */
5257 if ((realLen + 1) > cbTok) {
5258 HeapFree( GetProcessHeap(), 0, pFormatA );
5259 return TYPE_E_BUFFERTOOSMALL;
5260 }
5261 *pData++ = TOK_END;
5262 realLen = realLen + 1;
5263
5264 /* Finally fill in the length */
5265 hdr->len = realLen;
5266 *pcbActual = realLen;
5267
5268#if 0
5269 { int i,j;
5270 for (i=0; i<realLen; i=i+0x10) {
5271 printf(" %4.4x : ", i);
5272 for (j=0; j<0x10 && (i+j < realLen); j++) {
5273 printf("%2.2x ", rgbTok[i+j]);
5274 }
5275 printf("\n");
5276 }
5277 }
5278#endif
5279 HeapFree( GetProcessHeap(), 0, pFormatA );
5280
5281 return S_OK;
5282}
5283
5284/**********************************************************************
5285 * VarFormatFromTokens [OLEAUT32.139]
5286 * FIXME: No account of flags or iFirstDay etc
5287 */
5288HRESULT WINAPI VarFormatFromTokens(LPVARIANT varIn, LPOLESTR format,
5289 LPBYTE pbTokCur, ULONG dwFlags, BSTR *pbstrOut,
5290 LCID lcid) {
5291
5292 FORMATHDR *hdr = (FORMATHDR *)pbTokCur;
5293 BYTE *pData = pbTokCur + sizeof (FORMATHDR);
5294 LPSTR pFormatA = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
5295 char output[BUFFER_MAX];
5296 char *pNextPos;
5297 int size, whichToken;
5298 VARIANTARG Variant;
5299 struct tm TM;
5300
5301
5302
5303 TRACE("'%s', %p %lx %p only date support\n", pFormatA, pbTokCur, dwFlags, pbstrOut);
5304 TRACE("varIn:\n");
5305 dump_Variant(varIn);
5306
5307 memset(output, 0x00, BUFFER_MAX);
5308 pNextPos = output;
5309
5310 while (*pData != TOK_END && ((pData - pbTokCur) <= (hdr->len))) {
5311
5312 TRACE("Output looks like : '%s'\n", output);
5313
5314 /* Convert varient to appropriate data type */
5315 whichToken = 0;
5316 while ((formatTokens[whichToken].tokenSize != 0x00) &&
5317 (formatTokens[whichToken].tokenId != *pData)) {
5318 whichToken++;
5319 }
5320
5321 /* Use Variant local from here downwards as always correct type */
5322 if (formatTokens[whichToken].tokenSize > 0 &&
5323 formatTokens[whichToken].varTypeRequired != 0) {
5324 VariantInit( &Variant );
5325 if (Coerce( &Variant, lcid, dwFlags, varIn,
5326 formatTokens[whichToken].varTypeRequired ) != S_OK) {
5327 HeapFree( GetProcessHeap(), 0, pFormatA );
5328 return DISP_E_TYPEMISMATCH;
5329 } else if (formatTokens[whichToken].varTypeRequired == VT_DATE) {
5330 if( DateToTm( V_UNION(&Variant,date), dwFlags, &TM ) == FALSE ) {
5331 HeapFree( GetProcessHeap(), 0, pFormatA );
5332 return E_INVALIDARG;
5333 }
5334 }
5335 }
5336
5337 TRACE("Looking for match on token '%x'\n", *pData);
5338 switch (*pData) {
5339 case TOK_COPY:
5340 TRACE("Copy from %d for %d bytes\n", *(pData+1), *(pData+2));
5341 memcpy(pNextPos, &pFormatA[*(pData+1)], *(pData+2));
5342 pNextPos = pNextPos + *(pData+2);
5343 pData = pData + 3;
5344 break;
5345
5346 case TOK_COLON :
5347 /* Get locale information - Time Seperator */
5348 size = GetLocaleInfoA(lcid, LOCALE_STIME, NULL, 0);
5349 GetLocaleInfoA(lcid, LOCALE_STIME, pNextPos, size);
5350 TRACE("TOK_COLON Time seperator is '%s'\n", pNextPos);
5351 pNextPos = pNextPos + size;
5352 pData = pData + 1;
5353 break;
5354
5355 case TOK_SLASH :
5356 /* Get locale information - Date Seperator */
5357 size = GetLocaleInfoA(lcid, LOCALE_SDATE, NULL, 0);
5358 GetLocaleInfoA(lcid, LOCALE_SDATE, pNextPos, size);
5359 TRACE("TOK_COLON Time seperator is '%s'\n", pNextPos);
5360 pNextPos = pNextPos + size;
5361 pData = pData + 1;
5362 break;
5363
5364 case TOK_d :
5365 sprintf(pNextPos, "%d", TM.tm_mday);
5366 pNextPos = pNextPos + strlen(pNextPos);
5367 pData = pData + 1;
5368 break;
5369
5370 case TOK_dd :
5371 sprintf(pNextPos, "%2.2d", TM.tm_mday);
5372 pNextPos = pNextPos + strlen(pNextPos);
5373 pData = pData + 1;
5374 break;
5375
5376 case TOK_w :
5377 sprintf(pNextPos, "%d", TM.tm_wday+1);
5378 pNextPos = pNextPos + strlen(pNextPos);
5379 pData = pData + 1;
5380 break;
5381
5382 case TOK_m :
5383 sprintf(pNextPos, "%d", TM.tm_mon+1);
5384 pNextPos = pNextPos + strlen(pNextPos);
5385 pData = pData + 1;
5386 break;
5387
5388 case TOK_mm :
5389 sprintf(pNextPos, "%2.2d", TM.tm_mon+1);
5390 pNextPos = pNextPos + strlen(pNextPos);
5391 pData = pData + 1;
5392 break;
5393
5394 case TOK_q :
5395 sprintf(pNextPos, "%d", ((TM.tm_mon+1)/4)+1);
5396 pNextPos = pNextPos + strlen(pNextPos);
5397 pData = pData + 1;
5398 break;
5399
5400 case TOK_y :
5401 sprintf(pNextPos, "%2.2d", TM.tm_yday+1);
5402 pNextPos = pNextPos + strlen(pNextPos);
5403 pData = pData + 1;
5404 break;
5405
5406 case TOK_yy :
5407 sprintf(pNextPos, "%2.2d", TM.tm_year);
5408 pNextPos = pNextPos + strlen(pNextPos);
5409 pData = pData + 1;
5410 break;
5411
5412 case TOK_yyyy :
5413 sprintf(pNextPos, "%4.4d", TM.tm_year);
5414 pNextPos = pNextPos + strlen(pNextPos);
5415 pData = pData + 1;
5416 break;
5417
5418 case TOK_h :
5419 sprintf(pNextPos, "%d", TM.tm_hour);
5420 pNextPos = pNextPos + strlen(pNextPos);
5421 pData = pData + 1;
5422 break;
5423
5424 case TOK_Hh :
5425 sprintf(pNextPos, "%2.2d", TM.tm_hour);
5426 pNextPos = pNextPos + strlen(pNextPos);
5427 pData = pData + 1;
5428 break;
5429
5430 case TOK_N :
5431 sprintf(pNextPos, "%d", TM.tm_min);
5432 pNextPos = pNextPos + strlen(pNextPos);
5433 pData = pData + 1;
5434 break;
5435
5436 case TOK_Nn :
5437 sprintf(pNextPos, "%2.2d", TM.tm_min);
5438 pNextPos = pNextPos + strlen(pNextPos);
5439 pData = pData + 1;
5440 break;
5441
5442 case TOK_S :
5443 sprintf(pNextPos, "%d", TM.tm_sec);
5444 pNextPos = pNextPos + strlen(pNextPos);
5445 pData = pData + 1;
5446 break;
5447
5448 case TOK_Ss :
5449 sprintf(pNextPos, "%2.2d", TM.tm_sec);
5450 pNextPos = pNextPos + strlen(pNextPos);
5451 pData = pData + 1;
5452 break;
5453
5454 /* FIXME: To Do! */
5455 case TOK_ttttt :
5456 case TOK_AMsPM :
5457 case TOK_amspm :
5458 case TOK_AsP :
5459 case TOK_asp :
5460 case TOK_AMPM :
5461 case TOK_c :
5462 case TOK_ddd :
5463 case TOK_dddd :
5464 case TOK_ddddd :
5465 case TOK_dddddd :
5466 case TOK_ww :
5467 case TOK_mmm :
5468 case TOK_mmmm :
5469 default:
5470 FIXME("Unhandled token for VarFormat %d\n", *pData);
5471 HeapFree( GetProcessHeap(), 0, pFormatA );
5472 return E_INVALIDARG;
5473 }
5474
5475 }
5476
5477 *pbstrOut = StringDupAtoBstr( output );
5478 HeapFree( GetProcessHeap(), 0, pFormatA );
5479 return S_OK;
5480}
5481
5482/**********************************************************************
5483 * VarFormat [OLEAUT32.87]
5484 *
5485 */
5486HRESULT WINAPI VarFormat(LPVARIANT varIn, LPOLESTR format,
5487 int firstDay, int firstWeek, ULONG dwFlags,
5488 BSTR *pbstrOut) {
5489
5490 LPSTR pNewString = NULL;
5491 HRESULT rc = S_OK;
5492
5493 TRACE("mostly stub! format='%s' day=%d, wk=%d, flags=%ld\n",
5494 debugstr_w(format), firstDay, firstWeek, dwFlags);
5495 TRACE("varIn:\n");
5496 dump_Variant(varIn);
5497
5498 /* Note: Must Handle references type Variants (contain ptrs
5499 to values rather than values */
5500
5501 /* Get format string */
5502 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
5503
5504 /* FIXME: Handle some simple pre-definted format strings : */
5505 if (((V_VT(varIn)&VT_TYPEMASK) == VT_CY) && (lstrcmpiA(pNewString, "Currency") == 0)) {
5506
5507 /* Can't use VarBstrFromCy as it does not put currency sign on nor decimal places */
5508 double curVal;
5509
5510
5511 /* Handle references type Variants (contain ptrs to values rather than values */
5512 if (V_VT(varIn)&VT_BYREF) {
5513 rc = VarR8FromCy(*(CY *)V_UNION(varIn,byref), &curVal);
5514 } else {
5515 rc = VarR8FromCy(V_UNION(varIn,cyVal), &curVal);
5516 }
5517
5518 if (rc == S_OK) {
5519 char tmpStr[BUFFER_MAX];
5520 sprintf(tmpStr, "%f", curVal);
5521 if (GetCurrencyFormatA(GetUserDefaultLCID(), dwFlags, tmpStr, NULL, pBuffer, BUFFER_MAX) == 0) {
5522 return E_FAIL;
5523 } else {
5524 *pbstrOut = StringDupAtoBstr( pBuffer );
5525 }
5526 }
5527
5528 } else if ((V_VT(varIn)&VT_TYPEMASK) == VT_DATE) {
5529
5530 /* Attempt to do proper formatting! */
5531 int firstToken = -1;
5532
5533 rc = VarTokenizeFormatString(format, pBuffer, sizeof(pBuffer), firstDay,
5534 firstWeek, GetUserDefaultLCID(), &firstToken);
5535 if (rc==S_OK) {
5536 rc = VarFormatFromTokens(varIn, format, pBuffer, dwFlags, pbstrOut, GetUserDefaultLCID());
5537 }
5538
5539 } else if ((V_VT(varIn)&VT_TYPEMASK) == VT_R8) {
5540 if (V_VT(varIn)&VT_BYREF) {
5541 sprintf(pBuffer, "%f", *(double *)V_UNION(varIn,byref));
5542 } else {
5543 sprintf(pBuffer, "%f", V_UNION(varIn,dblVal));
5544 }
5545
5546 *pbstrOut = StringDupAtoBstr( pBuffer );
5547
5548 } else {
5549 FIXME("VarFormat: Unsupported format %d!\n", V_VT(varIn)&VT_TYPEMASK);
5550 *pbstrOut = StringDupAtoBstr( "??" );
5551 }
5552
5553 /* Free allocated storage */
5554 HeapFree( GetProcessHeap(), 0, pNewString );
5555 TRACE("result: '%s'\n", debugstr_w(*pbstrOut));
5556 return rc;
5557}
5558
5559/**********************************************************************
5560 * VarCyMulI4 [OLEAUT32.304]
5561 * Multiply currency value by integer
5562 */
5563HRESULT WINAPI VarCyMulI4(CY cyIn, LONG mulBy, CY *pcyOut) {
5564
5565 double cyVal = 0;
5566 HRESULT rc = S_OK;
5567
5568 rc = VarR8FromCy(cyIn, &cyVal);
5569 if (rc == S_OK) {
5570 rc = VarCyFromR8((cyVal * (double) mulBy), pcyOut);
5571 TRACE("Multiply %f by %ld = %f [%ld,%lu]\n", cyVal, mulBy, (cyVal * (double) mulBy),
[21916]5572 pcyOut->DUMMYSTRUCTNAME_DOT Hi, pcyOut->DUMMYSTRUCTNAME_DOT Lo);
[9400]5573 }
5574 return rc;
5575}
Note: See TracBrowser for help on using the repository browser.