Changeset 9400 for trunk/src/oleaut32/variant.c
- Timestamp:
- Nov 12, 2002, 6:07:48 PM (23 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/oleaut32/variant.c
r8450 r9400 36 36 37 37 #include "config.h" 38 38 39 39 #include <string.h> 40 40 #include <stdlib.h> … … 53 53 #include "winerror.h" 54 54 #include "parsedt.h" 55 #include "typelib.h" 55 56 56 57 WINE_DEFAULT_DEBUG_CHANNEL(ole); … … 100 101 * 400 then it is a leap year. 101 102 */ 102 /* According to postgreSQL date parsing functions there is 103 * a leap year when this expression is true. 104 * (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0))) 105 * So according to this there is 365.2515 days in one year. 106 * One + every four years: 1/4 -> 365.25 107 * One - every 100 years: 1/100 -> 365.01 108 * One + every 400 years: 1/400 -> 365.0025 109 */ 110 /* static const double DAYS_IN_ONE_YEAR = 365.2515; 103 104 /* 105 * Use 365 days/year and a manual calculation for leap year days 106 * to keep arithmetic simple 107 */ 108 static 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 111 114 * 112 * ^^ Might this be the key to an easy way to factor large prime numbers? 113 * Let's try using arithmetic. <lawson_whitney@juno.com> 7 Mar 2000 114 */ 115 static const double DAYS_IN_ONE_YEAR = 365.2425; 116 115 */ 116 /* Pre defined tokens */ 117 #define TOK_COPY 0x00 118 #define TOK_END 0x02 119 #define LARGEST_TOKENID 6 120 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 154 155 typedef struct tagFORMATTOKEN { 156 char *str; 157 BYTE tokenSize; 158 BYTE tokenId; 159 int varTypeRequired; 160 } FORMATTOKEN; 161 162 typedef struct tagFORMATHDR { 163 BYTE len; 164 BYTE hex3; 165 BYTE hex6; 166 BYTE reserved[8]; 167 } FORMATHDR; 168 169 FORMATTOKEN formatTokens[] = { /* FIXME: Only date formats so far */ 170 {":" , 1, TOK_COLON , 0}, 171 {"/" , 1, TOK_SLASH , 0}, 172 {"c" , 1, TOK_c , VT_DATE}, 173 {"dddddd", 6, TOK_dddddd , VT_DATE}, 174 {"ddddd" , 5, TOK_ddddd , VT_DATE}, 175 {"dddd" , 4, TOK_dddd , VT_DATE}, 176 {"ddd" , 3, TOK_ddd , VT_DATE}, 177 {"dd" , 2, TOK_dd , VT_DATE}, 178 {"d" , 1, TOK_d , VT_DATE}, 179 {"ww" , 2, TOK_ww , VT_DATE}, 180 {"w" , 1, TOK_w , VT_DATE}, 181 {"mmmm" , 4, TOK_mmmm , VT_DATE}, 182 {"mmm" , 3, TOK_mmm , VT_DATE}, 183 {"mm" , 2, TOK_mm , VT_DATE}, 184 {"m" , 1, TOK_m , VT_DATE}, 185 {"q" , 1, TOK_q , VT_DATE}, 186 {"yyyy" , 4, TOK_yyyy , VT_DATE}, 187 {"yy" , 2, TOK_yy , VT_DATE}, 188 {"y" , 1, TOK_y , VT_DATE}, 189 {"h" , 1, TOK_h , VT_DATE}, 190 {"Hh" , 2, TOK_Hh , VT_DATE}, 191 {"Nn" , 2, TOK_Nn , VT_DATE}, 192 {"N" , 1, TOK_N , VT_DATE}, 193 {"S" , 1, TOK_S , VT_DATE}, 194 {"Ss" , 2, TOK_Ss , VT_DATE}, 195 {"ttttt" , 5, TOK_ttttt , VT_DATE}, 196 {"AM/PM" , 5, TOK_AMsPM , VT_DATE}, 197 {"am/pm" , 5, TOK_amspm , VT_DATE}, 198 {"A/P" , 3, TOK_AsP , VT_DATE}, 199 {"a/p" , 3, TOK_asp , VT_DATE}, 200 {"AMPM" , 4, TOK_AMPM , VT_DATE}, 201 {0x00 , 0, 0 , VT_NULL} 202 }; 117 203 118 204 /****************************************************************************** … … 248 334 int leapYear = 0; 249 335 250 if( (pTm->tm_year - 1900) < 0 ) return FALSE; 336 /* Hmmm... An uninitialized Date in VB is December 30 1899 so 337 Start at 0. This is the way DATE is defined. */ 251 338 252 339 /* Start at 1. This is the way DATE is defined. … … 257 344 *pDateOut = 1; 258 345 259 /* Add the number of days corresponding to 260 * tm_year. 261 */ 262 *pDateOut += (pTm->tm_year - 1900) * 365; 263 264 /* Add the leap days in the previous years between now and 1900. 265 * Note a leap year is one that is a multiple of 4 266 * but not of a 100. Except if it is a multiple of 267 * 400 then it is a leap year. 268 */ 269 *pDateOut += ( (pTm->tm_year - 1) / 4 ) - ( 1900 / 4 ); 270 *pDateOut -= ( (pTm->tm_year - 1) / 100 ) - ( 1900 / 100 ); 271 *pDateOut += ( (pTm->tm_year - 1) / 400 ) - ( 1900 / 400 ); 272 273 /* Set the leap year flag if the 274 * current year specified by tm_year is a 275 * leap year. This will be used to add a day 276 * to the day count. 277 */ 278 if( isleap( pTm->tm_year ) ) 279 leapYear = 1; 280 281 /* Add the number of days corresponding to 282 * the month. 283 */ 284 switch( pTm->tm_mon ) 285 { 286 case 2: 287 *pDateOut += 31; 288 break; 289 case 3: 290 *pDateOut += ( 59 + leapYear ); 291 break; 292 case 4: 293 *pDateOut += ( 90 + leapYear ); 294 break; 295 case 5: 296 *pDateOut += ( 120 + leapYear ); 297 break; 298 case 6: 299 *pDateOut += ( 151 + leapYear ); 300 break; 301 case 7: 302 *pDateOut += ( 181 + leapYear ); 303 break; 304 case 8: 305 *pDateOut += ( 212 + leapYear ); 306 break; 307 case 9: 308 *pDateOut += ( 243 + leapYear ); 309 break; 310 case 10: 311 *pDateOut += ( 273 + leapYear ); 312 break; 313 case 11: 314 *pDateOut += ( 304 + leapYear ); 315 break; 316 case 12: 317 *pDateOut += ( 334 + leapYear ); 318 break; 346 if( (pTm->tm_year - 1900) >= 0 ) { 347 348 /* Add the number of days corresponding to 349 * tm_year. 350 */ 351 *pDateOut += (pTm->tm_year - 1900) * 365; 352 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 ); 362 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; 319 420 } 320 /* Add the number of days in this month. 321 */ 322 *pDateOut += pTm->tm_mday; 323 324 /* Add the number of seconds, minutes, and hours 325 * to the DATE. Note these are the fracionnal part 326 * of the DATE so seconds / number of seconds in a day. 327 */ 421 328 422 *pDateOut += pTm->tm_hour / 24.0; 329 423 *pDateOut += pTm->tm_min / 1440.0; … … 346 440 * Returns TRUE if successful. 347 441 */ 348 staticBOOL DateToTm( DATE dateIn, DWORD dwFlags, struct tm* pTm )442 BOOL DateToTm( DATE dateIn, DWORD dwFlags, struct tm* pTm ) 349 443 { 350 444 double decimalPart = 0.0; 351 445 double wholePart = 0.0; 352 353 /* Do not process dates smaller than January 1, 1900.354 * Which corresponds to 2.0 in the windows DATE format.355 */356 if( dateIn < 2.0 ) return FALSE;357 446 358 447 memset(pTm,0,sizeof(*pTm)); … … 365 454 * This simplifies the processing of the DATE value. 366 455 */ 456 decimalPart = fmod( dateIn, 1.0 ); /* Do this before the -1, otherwise 0.xx goes negative */ 367 457 dateIn -= 1.0; 368 369 458 wholePart = (double) floor( dateIn ); 370 decimalPart = fmod( dateIn, wholePart );371 459 372 460 if( !(dwFlags & VAR_TIMEVALUEONLY) ) 373 461 { 374 int nDay = 0;462 unsigned int nDay = 0; 375 463 int leapYear = 0; 376 464 double yearsSince1900 = 0; 377 /* Start at 1900, this is where the DATE time 0.0 starts. 378 */ 379 pTm->tm_year = 1900; 380 /* find in what year the day in the "wholePart" falls into. 381 * add the value to the year field. 382 */ 383 yearsSince1900 = floor( (wholePart / DAYS_IN_ONE_YEAR) + 0.001 ); 384 pTm->tm_year += yearsSince1900; 385 /* determine if this is a leap year. 386 */ 387 if( isleap( pTm->tm_year ) ) 388 { 389 leapYear = 1; 390 wholePart++; 391 } 392 393 /* find what day of that year the "wholePart" corresponds to. 394 * Note: nDay is in [1-366] format 395 */ 396 nDay = (int) ( wholePart - floor( yearsSince1900 * DAYS_IN_ONE_YEAR ) ); 397 /* Set the tm_yday value. 398 * Note: The day must be converted from [1-366] to [0-365] 399 */ 400 /*pTm->tm_yday = nDay - 1;*/ 401 /* find which month this day corresponds to. 402 */ 403 if( nDay <= 31 ) 404 { 405 pTm->tm_mday = nDay; 406 pTm->tm_mon = 0; 407 } 408 else if( nDay <= ( 59 + leapYear ) ) 409 { 410 pTm->tm_mday = nDay - 31; 411 pTm->tm_mon = 1; 412 } 413 else if( nDay <= ( 90 + leapYear ) ) 414 { 415 pTm->tm_mday = nDay - ( 59 + leapYear ); 416 pTm->tm_mon = 2; 417 } 418 else if( nDay <= ( 120 + leapYear ) ) 419 { 420 pTm->tm_mday = nDay - ( 90 + leapYear ); 421 pTm->tm_mon = 3; 422 } 423 else if( nDay <= ( 151 + leapYear ) ) 424 { 425 pTm->tm_mday = nDay - ( 120 + leapYear ); 426 pTm->tm_mon = 4; 427 } 428 else if( nDay <= ( 181 + leapYear ) ) 429 { 430 pTm->tm_mday = nDay - ( 151 + leapYear ); 431 pTm->tm_mon = 5; 432 } 433 else if( nDay <= ( 212 + leapYear ) ) 434 { 435 pTm->tm_mday = nDay - ( 181 + leapYear ); 436 pTm->tm_mon = 6; 437 } 438 else if( nDay <= ( 243 + leapYear ) ) 439 { 440 pTm->tm_mday = nDay - ( 212 + leapYear ); 441 pTm->tm_mon = 7; 442 } 443 else if( nDay <= ( 273 + leapYear ) ) 444 { 445 pTm->tm_mday = nDay - ( 243 + leapYear ); 446 pTm->tm_mon = 8; 447 } 448 else if( nDay <= ( 304 + leapYear ) ) 449 { 450 pTm->tm_mday = nDay - ( 273 + leapYear ); 451 pTm->tm_mon = 9; 452 } 453 else if( nDay <= ( 334 + leapYear ) ) 454 { 455 pTm->tm_mday = nDay - ( 304 + leapYear ); 456 pTm->tm_mon = 10; 457 } 458 else if( nDay <= ( 365 + leapYear ) ) 459 { 460 pTm->tm_mday = nDay - ( 334 + leapYear ); 461 pTm->tm_mon = 11; 465 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 } 462 577 } 463 578 } … … 466 581 /* find the number of seconds in this day. 467 582 * fractional part times, hours, minutes, seconds. 583 * Note: 0.1 is hack to ensure figures come out in whole numbers 584 * due to floating point inaccuracies 468 585 */ 469 586 pTm->tm_hour = (int) ( decimalPart * 24 ); 470 587 pTm->tm_min = (int) ( ( ( decimalPart * 24 ) - pTm->tm_hour ) * 60 ); 471 pTm->tm_sec = (int) ( ( ( decimalPart * 24 * 60 ) - ( pTm->tm_hour * 60 ) - pTm->tm_min ) * 60 ); 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); 472 591 } 473 592 return TRUE; … … 521 640 break; 522 641 case( VT_BSTR ): 642 case( VT_DISPATCH ): 643 case( VT_UNKNOWN ): 523 644 size = sizeof(void*); 524 645 break; 525 646 case( VT_CY ): 526 case( VT_DISPATCH ): 527 case( VT_UNKNOWN ): 528 case( VT_DECIMAL ): 647 size = sizeof(CY); 648 break; 649 case( VT_DECIMAL ): /* hmm, tricky, DECIMAL is only VT_BYREF */ 529 650 default: 530 651 FIXME("Add size information for type vt=%d\n", V_VT(parg) & VT_TYPEMASK ); … … 536 657 /****************************************************************************** 537 658 * StringDupAtoBstr [INTERNAL] 538 * 659 * 539 660 */ 540 661 static BSTR StringDupAtoBstr( char* strIn ) … … 563 684 nSign = (d >= 0.0) ? 1 : -1; 564 685 d = fabs( d ); 565 686 566 687 /* Remove the decimals. 567 688 */ … … 630 751 str[0] = '\0'; 631 752 strToken = strtok( pNewString, strOfCharToRemove ); 632 while( strToken != NULL ) { 753 while( strToken != NULL ) { 633 754 strcat( str, strToken ); 634 755 strToken = strtok( NULL, strOfCharToRemove ); … … 671 792 int nTokens = 0; 672 793 LPSTR pChar = NULL; 673 794 674 795 /* Check if we have a valid argument 675 796 */ … … 684 805 */ 685 806 strToken = strtok( strRealString, " " ); 686 while( strToken != NULL ) { 687 nTokens++; 688 strToken = strtok( NULL, " " ); 807 while( strToken != NULL ) { 808 nTokens++; 809 strToken = strtok( NULL, " " ); 689 810 } 690 811 … … 778 899 case '7': 779 900 case '8': 780 case '9': 901 case '9': 781 902 if( bFirstDigitsProcessed == FALSE ) 782 903 { … … 824 945 /* If DecimalPoint... 825 946 */ 826 case '.': 947 case '.': 827 948 if( bDecimalPointProcessed || 828 949 bSecondDigitsProcessed || … … 894 1015 vtFrom = V_VT(ps) & VT_TYPEMASK; 895 1016 896 1017 897 1018 /* Note: Since "long" and "int" values both have 4 bytes and are 898 1019 * both signed integers "int" will be treated as "long" in the … … 901 1022 */ 902 1023 903 /* Trivial Case: If the coercion is from two types that are 1024 /* Trivial Case: If the coercion is from two types that are 904 1025 * identical then we can blindly copy from one argument to another.*/ 905 1026 if ((vt==vtFrom)) … … 1247 1368 } 1248 1369 break; 1249 1370 1250 1371 case( VT_R4 ): 1251 1372 switch( vtFrom ) … … 1610 1731 break; 1611 1732 } 1612 1733 1613 1734 return res; 1614 1735 } … … 1656 1777 res = DISP_E_BADVARTYPE; 1657 1778 } 1658 1779 1659 1780 } 1660 1781 else … … 1662 1783 res = ValidateVtRange( vt ); 1663 1784 } 1664 1785 1665 1786 return res; 1666 1787 } … … 1689 1810 res = DISP_E_BADVARTYPE; 1690 1811 } 1691 1812 1692 1813 } 1693 1814 else … … 1695 1816 res = ValidateVtRange( vt ); 1696 1817 } 1697 1818 1698 1819 return res; 1699 1820 } … … 1770 1891 } 1771 1892 } 1772 1893 1773 1894 /* 1774 1895 * Empty all the fields and mark the type as empty. … … 1800 1921 { 1801 1922 res = VariantClear( pvargDest ); 1802 1923 1803 1924 if( res == S_OK ) 1804 1925 { … … 1854 1975 } 1855 1976 } 1856 1977 1857 1978 V_VT(pvargDest) = V_VT(pvargSrc); 1858 } 1979 } 1859 1980 } 1860 1981 } … … 1880 2001 if( res != S_OK ) 1881 2002 return res; 1882 2003 1883 2004 if( V_VT(pvargSrc) & VT_BYREF ) 1884 2005 { … … 1931 2052 * If the inner Variant itself contains an 1932 2053 * other inner variant the E_INVALIDARG error is 1933 * returned. 2054 * returned. 1934 2055 */ 1935 2056 if( pvargSrc->n1.n2.wReserved1 & PROCESSING_INNER_VARIANT ) … … 1948 2069 */ 1949 2070 (V_UNION(pvargSrc,pvarVal))->n1.n2.wReserved1 |= PROCESSING_INNER_VARIANT; 1950 2071 1951 2072 /* Dereference the inner variant. 1952 2073 */ … … 2011 2132 VARIANTARG varg; 2012 2133 VariantInit( &varg ); 2013 2134 2014 2135 TRACE("(%p, %p, %ld, %u, %u) vt=%d\n", pvargDest, pvargSrc, lcid, wFlags, vt, V_VT(pvargSrc)); 2136 TRACE("Src Var:\n"); 2137 dump_Variant(pvargSrc); 2015 2138 2016 2139 /* validate our source argument. … … 2056 2179 VariantClear( &Variant ); 2057 2180 } 2058 2181 2059 2182 } 2060 2183 else … … 2068 2191 */ 2069 2192 VariantClear( &varg ); 2070 2193 2071 2194 /* set the type of the destination 2072 2195 */ … … 2074 2197 V_VT(pvargDest) = vt; 2075 2198 2199 TRACE("Dest Var:\n"); 2200 dump_Variant(pvargDest); 2201 2076 2202 return res; 2077 2203 } … … 2095 2221 2096 2222 *pbOut = (BYTE) sIn; 2097 2223 2098 2224 return S_OK; 2099 2225 } … … 2114 2240 2115 2241 *pbOut = (BYTE) lIn; 2116 2242 2117 2243 return S_OK; 2118 2244 } … … 2135 2261 2136 2262 *pbOut = (BYTE) fltIn; 2137 2263 2138 2264 return S_OK; 2139 2265 } … … 2264 2390 */ 2265 2391 dValue = atof( pNewString ); 2266 2392 2267 2393 /* We don't need the string anymore so free it. 2268 2394 */ … … 2288 2414 HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut) { 2289 2415 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000); 2290 2416 2291 2417 if (t > UI1_MAX || t < UI1_MIN) return DISP_E_OVERFLOW; 2292 2418 2293 2419 *pbOut = (BYTE)t; 2294 2420 return S_OK; … … 2303 2429 2304 2430 *psOut = (short) bIn; 2305 2431 2306 2432 return S_OK; 2307 2433 } … … 2322 2448 2323 2449 *psOut = (short) lIn; 2324 2450 2325 2451 return S_OK; 2326 2452 } … … 2470 2596 */ 2471 2597 dValue = atof( pNewString ); 2472 2598 2473 2599 /* We don't need the string anymore so free it. 2474 2600 */ … … 2494 2620 HRESULT WINAPI VarI2FromCy(CY cyIn, short* psOut) { 2495 2621 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000); 2496 2622 2497 2623 if (t > I2_MAX || t < I2_MIN) return DISP_E_OVERFLOW; 2498 2624 2499 2625 *psOut = (SHORT)t; 2500 2626 return S_OK; … … 2663 2789 */ 2664 2790 dValue = atof( pNewString ); 2665 2791 2666 2792 /* We don't need the string anymore so free it. 2667 2793 */ … … 2687 2813 HRESULT WINAPI VarI4FromCy(CY cyIn, LONG* plOut) { 2688 2814 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000); 2689 2815 2690 2816 if (t > I4_MAX || t < I4_MIN) return DISP_E_OVERFLOW; 2691 2817 2692 2818 *plOut = (LONG)t; 2693 2819 return S_OK; … … 2838 2964 */ 2839 2965 dValue = atof( pNewString ); 2840 2966 2841 2967 /* We don't need the string anymore so free it. 2842 2968 */ … … 2861 2987 HRESULT WINAPI VarR4FromCy(CY cyIn, FLOAT* pfltOut) { 2862 2988 *pfltOut = (FLOAT)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000); 2863 2989 2864 2990 return S_OK; 2865 2991 } … … 2981 3107 LPSTR pNewString = NULL; 2982 3108 2983 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pdblOut ); 3109 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn ); 3110 TRACE("( %s, %ld, %ld, %p ), stub\n", pNewString, lcid, dwFlags, pdblOut ); 2984 3111 2985 3112 /* Check if we have a valid argument 2986 3113 */ 2987 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );2988 3114 RemoveCharacterFromString( pNewString, "," ); 2989 3115 if( IsValidRealString( pNewString ) == FALSE ) … … 2995 3121 */ 2996 3122 dValue = atof( pNewString ); 2997 3123 2998 3124 /* We don't need the string anymore so free it. 2999 3125 */ … … 3011 3137 HRESULT WINAPI VarR8FromCy(CY cyIn, double* pdblOut) { 3012 3138 *pdblOut = (double)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000); 3013 3139 TRACE("%lu %ld -> %f\n", cyIn.s.Hi, cyIn.s.Lo, *pdblOut); 3014 3140 return S_OK; 3015 3141 } … … 3100 3226 * 3101 3227 * The formats for the date part are has follows: 3102 * mm/[dd/][yy]yy 3228 * mm/[dd/][yy]yy 3103 3229 * [dd/]mm/[yy]yy 3104 * [yy]yy/mm/dd 3230 * [yy]yy/mm/dd 3105 3231 * January dd[,] [yy]yy 3106 3232 * dd January [yy]yy … … 3109 3235 * 3110 3236 * The formats for the date and time string are has follows. 3111 * date[whitespace][time] 3237 * date[whitespace][time] 3112 3238 * [time][whitespace]date 3113 3239 * … … 3135 3261 ret = DISP_E_TYPEMISMATCH; 3136 3262 } 3137 3138 3263 TRACE("Return value %f\n", *pdateOut); 3139 3264 return ret; 3140 3265 } … … 3218 3343 3219 3344 *pbstrOut = StringDupAtoBstr( pBuffer ); 3220 3345 3221 3346 return S_OK; 3222 3347 } … … 3277 3402 */ 3278 3403 HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut) { 3279 FIXME("([cyIn], %08lx, %08lx, %p), stub.\n", lcid, dwFlags, pbstrOut); 3280 return E_NOTIMPL; 3281 } 3282 3283 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; 3416 } 3417 3418 3284 3419 /****************************************************************************** 3285 3420 * VarBstrFromDate [OLEAUT32.114] … … 3316 3451 memset( &TM, 0, sizeof(TM) ); 3317 3452 3318 TRACE("( % f, %ld, %ld, %p ), stub\n", dateIn, lcid, dwFlags, pbstrOut );3453 TRACE("( %20.20f, %ld, %ld, %p ), stub\n", dateIn, lcid, dwFlags, pbstrOut ); 3319 3454 3320 3455 if( DateToTm( dateIn, dwFlags, &TM ) == FALSE ) … … 3330 3465 strftime( pBuffer, BUFFER_MAX, "%x %X", &TM ); 3331 3466 3467 TRACE("result: %s\n", pBuffer); 3332 3468 *pbstrOut = StringDupAtoBstr( pBuffer ); 3333 3334 3469 return S_OK; 3335 3470 } … … 3508 3643 3509 3644 HeapFree( GetProcessHeap(), 0, pNewString ); 3510 3645 3511 3646 return ret; 3512 3647 } … … 3555 3690 if (cyIn.s.Hi || cyIn.s.Lo) *pboolOut = -1; 3556 3691 else *pboolOut = 0; 3557 3692 3558 3693 return S_OK; 3559 3694 } … … 3688 3823 */ 3689 3824 dValue = atof( pNewString ); 3690 3825 3691 3826 /* We don't need the string anymore so free it. 3692 3827 */ … … 3758 3893 HRESULT WINAPI VarI1FromCy(CY cyIn, CHAR* pcOut) { 3759 3894 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000); 3760 3895 3761 3896 if (t > CHAR_MAX || t < CHAR_MIN) return DISP_E_OVERFLOW; 3762 3897 3763 3898 *pcOut = (CHAR)t; 3764 3899 return S_OK; … … 3887 4022 */ 3888 4023 dValue = atof( pNewString ); 3889 4024 3890 4025 /* We don't need the string anymore so free it. 3891 4026 */ … … 3936 4071 TRACE("( %ld, %p ), stub\n", ulIn, puiOut ); 3937 4072 3938 if( ulIn < UI2_MIN || ulIn> UI2_MAX )4073 if( ulIn > UI2_MAX ) 3939 4074 { 3940 4075 return DISP_E_OVERFLOW; … … 3968 4103 */ 3969 4104 dValue = atof( pNewString ); 3970 4105 3971 4106 /* We don't need the string anymore so free it. 3972 4107 */ … … 3992 4127 HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut) { 3993 4128 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000); 3994 4129 3995 4130 if (t > UI2_MAX || t < UI2_MIN) return DISP_E_OVERFLOW; 3996 4131 3997 4132 *pusOut = (USHORT)t; 3998 4133 3999 4134 return S_OK; 4000 4135 } … … 4036 4171 TRACE("( %ld, %p ), stub\n", lIn, pulOut ); 4037 4172 4038 if( lIn < UI4_MIN)4173 if( lIn < 0 ) 4039 4174 { 4040 4175 return DISP_E_OVERFLOW; … … 4140 4275 HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG* pulOut) { 4141 4276 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000); 4142 4277 4143 4278 if (t > UI4_MAX || t < UI4_MIN) return DISP_E_OVERFLOW; 4144 4279 … … 4180 4315 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0); 4181 4316 if (lIn < 0) pcyOut->s.Hi--; 4182 4317 4183 4318 return S_OK; 4184 4319 } … … 4193 4328 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0); 4194 4329 if (fltIn < 0) pcyOut->s.Hi--; 4195 4330 4196 4331 return S_OK; 4197 4332 } … … 4225 4360 /********************************************************************** 4226 4361 * VarCyFromStr [OLEAUT32.104] 4362 * FIXME: Never tested with decimal seperator other than '.' 4227 4363 */ 4228 4364 HRESULT WINAPI VarCyFromStr(OLECHAR *strIn, LCID lcid, ULONG dwFlags, CY *pcyOut) { 4229 FIXME("(%p, %08lx, %08lx, %p), stub.\n", strIn, lcid, dwFlags, pcyOut); 4230 return E_NOTIMPL; 4231 } 4232 4233 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); 4412 } 4413 4414 4234 4415 /********************************************************************** 4235 4416 * VarCyFromBool [OLEAUT32.106] … … 4240 4421 else pcyOut->s.Hi = 0; 4241 4422 pcyOut->s.Lo = (ULONG)boolIn * (ULONG)10000; 4242 4423 4243 4424 return S_OK; 4244 4425 } … … 4252 4433 else pcyOut->s.Hi = 0; 4253 4434 pcyOut->s.Lo = (ULONG)cIn * (ULONG)10000; 4254 4435 4255 4436 return S_OK; 4256 4437 } … … 4263 4444 pcyOut->s.Hi = 0; 4264 4445 pcyOut->s.Lo = (ULONG)usIn * (ULONG)10000; 4265 4446 4266 4447 return S_OK; 4267 4448 } … … 4275 4456 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0); 4276 4457 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0); 4277 4458 4278 4459 return S_OK; 4279 4460 } … … 4291 4472 4292 4473 TRACE("( 0x%x, 0x%x, %p ), stub\n", wDosDate, wDosTime, pvtime ); 4293 4474 4294 4475 t.tm_sec = (wDosTime & 0x001f) * 2; 4295 4476 t.tm_min = (wDosTime & 0x07e0) >> 5; 4296 4477 t.tm_hour = (wDosTime & 0xf800) >> 11; 4297 4478 4298 4479 t.tm_mday = (wDosDate & 0x001f); 4299 4480 t.tm_mon = (wDosDate & 0x01e0) >> 5; … … 4312 4493 int i,lastent=0; 4313 4494 int cDig; 4495 BOOL foundNum=FALSE; 4496 4314 4497 FIXME("(%s,flags=%lx,....), partial stub!\n",debugstr_w(strIn),dwFlags); 4315 4498 FIXME("numparse: cDig=%d, InFlags=%lx\n",pnumprs->cDig,pnumprs->dwInFlags); 4316 4499 4317 4500 /* The other struct components are to be set by us */ 4318 4319 4501 memset(rgbDig,0,pnumprs->cDig); 4502 4503 /* FIXME: Just patching some values in */ 4504 pnumprs->nPwr10 = 0; 4505 pnumprs->nBaseShift = 0; 4506 pnumprs->cchUsed = lastent; 4507 pnumprs->dwOutFlags = NUMPRS_DECIMAL; 4320 4508 4321 4509 cDig = 0; 4322 4510 for (i=0; strIn[i] ;i++) { 4323 4511 if ((strIn[i]>='0') && (strIn[i]<='9')) { 4512 foundNum = TRUE; 4324 4513 if (pnumprs->cDig > cDig) { 4325 4514 *(rgbDig++)=strIn[i]-'0'; … … 4327 4516 lastent = i; 4328 4517 } 4329 } 4518 } else if ((strIn[i]=='-') && (foundNum==FALSE)) { 4519 pnumprs->dwOutFlags |= NUMPRS_NEG; 4520 } 4330 4521 } 4331 4522 pnumprs->cDig = cDig; 4332 4333 /* FIXME: Just patching some values in */ 4334 pnumprs->nPwr10 = 0; 4335 pnumprs->nBaseShift = 0; 4336 pnumprs->cchUsed = lastent; 4337 pnumprs->dwOutFlags = NUMPRS_DECIMAL; 4523 TRACE("numparse out: cDig=%d, OutFlags=%lx\n",pnumprs->cDig,pnumprs->dwOutFlags); 4338 4524 return S_OK; 4339 4525 } … … 4348 4534 DWORD xint; 4349 4535 int i; 4350 FIXME("( ,dwVtBits=%lx,....), partial stub!\n",dwVtBits);4536 FIXME("(..,dwVtBits=%lx,....), partial stub!\n",dwVtBits); 4351 4537 4352 4538 xint = 0; 4353 4539 for (i=0;i<pnumprs->cDig;i++) 4354 4540 xint = xint*10 + rgbDig[i]; 4541 4542 if (pnumprs->dwOutFlags & NUMPRS_NEG) { 4543 xint = xint * -1; 4544 } 4355 4545 4356 4546 VariantInit(pvar); … … 4364 4554 V_UNION(pvar,dblVal) = xint; 4365 4555 return S_OK; 4366 } else { 4367 FIXME("vtbitmask is unsupported %lx\n",dwVtBits); 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) ); 4572 TRACE("Calculated cy is %ld,%lu\n", V_UNION(pvar,cyVal).s.Hi, V_UNION(pvar,cyVal).s.Lo); 4573 return VarCyFromInt( (int) xint, &V_UNION(pvar,cyVal) ); 4574 } 4575 4576 FIXME("vtbitmask is unsupported %lx, int=%d\n",dwVtBits, (int) xint); 4368 4577 return E_FAIL; 4369 } 4370 } 4371 4578 } 4579 4580 4581 /********************************************************************** 4582 * VarFormatDateTime [OLEAUT32.97] 4583 */ 4584 HRESULT 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 */ 4593 HRESULT 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 } 4372 4598 4373 4599 /********************************************************************** … … 4403 4629 HRESULT WINAPI SystemTimeToVariantTime( LPSYSTEMTIME lpSystemTime, double *pvtime ) 4404 4630 { 4405 static const BYTE Days_Per_Month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};4406 static const BYTE Days_Per_Month_LY[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};4407 4408 4631 struct tm t; 4409 4632 … … 4420 4643 4421 4644 t.tm_mday = lpSystemTime->wDay; 4422 t.tm_mon = lpSystemTime->wMonth ;4645 t.tm_mon = lpSystemTime->wMonth - 1; /* tm_mon is 0..11, wMonth is 1..12 */ 4423 4646 t.tm_year = lpSystemTime->wYear; 4424 4647 … … 4427 4650 else 4428 4651 { 4652 double tmpDate; 4653 long firstDayOfNextYear; 4654 long thisDay; 4655 long leftInYear; 4656 long result; 4657 4658 double decimalPart = 0.0; 4659 4429 4660 t.tm_sec = lpSystemTime->wSecond; 4430 4661 t.tm_min = lpSystemTime->wMinute; 4431 4662 t.tm_hour = lpSystemTime->wHour; 4432 4663 4433 if (isleap(lpSystemTime->wYear) ) 4434 t.tm_mday = Days_Per_Month_LY[13 - lpSystemTime->wMonth] - lpSystemTime->wDay; 4435 else 4436 t.tm_mday = Days_Per_Month[13 - lpSystemTime->wMonth] - lpSystemTime->wDay; 4437 4438 t.tm_mon = 13 - lpSystemTime->wMonth; 4664 /* Step year forward the same number of years before 1900 */ 4439 4665 t.tm_year = 1900 + 1899 - lpSystemTime->wYear; 4440 4666 t.tm_mon = lpSystemTime->wMonth - 1; 4667 t.tm_mday = lpSystemTime->wDay; 4668 4669 /* Calculate date */ 4441 4670 TmToDATE( &t, pvtime ); 4442 4671 4443 *pvtime *= -1; 4672 thisDay = (double) floor( *pvtime ); 4673 decimalPart = fmod( *pvtime, thisDay ); 4674 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); 4444 4699 4445 4700 return 1; … … 4468 4723 struct tm r; 4469 4724 4470 TRACE(" Variant = %f SYSTEMTIME ptr %p ", vtime, lpSystemTime);4725 TRACE(" Variant = %f SYSTEMTIME ptr %p\n", vtime, lpSystemTime); 4471 4726 4472 4727 if (vtime >= 0) … … 4619 4874 *datein = t; 4620 4875 4621 if (i) dwFlags = 0; /*VAR_VALIDDATE*/ 4622 else dwFlags = 0; 4623 4624 return i; 4876 if (i) return S_OK; 4877 else return E_INVALIDARG; 4625 4878 } 4626 4879 4627 4880 4628 4881 /********************************************************************** 4629 * VarBstrCmp [OLEAUT32. 440]4882 * VarBstrCmp [OLEAUT32.314] 4630 4883 * 4631 * flags can be: 4884 * flags can be: 4632 4885 * NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS 4633 4886 * NORM_IGNORESTRINGWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA … … 4636 4889 HRESULT WINAPI VarBstrCmp(BSTR left, BSTR right, LCID lcid, DWORD flags) 4637 4890 { 4638 DWORD r; 4639 4640 FIXME("( %s %s %ld %lx ) partial stub\n", debugstr_w(left), debugstr_w(right), lcid, flags); 4641 4642 if((!left) || (!right)) 4643 return VARCMP_NULL; 4891 INT r; 4892 4893 TRACE("( %s %s %ld %lx ) partial stub\n", debugstr_w(left), debugstr_w(right), lcid, flags); 4894 4895 /* Contrary to the MSDN, this returns eq for null vs null, null vs L"" and L"" vs NULL */ 4896 if((!left) || (!right)) { 4897 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 } 4644 4902 4645 4903 if(flags&NORM_IGNORECASE) … … 4657 4915 4658 4916 /********************************************************************** 4659 * VarBstrCat [OLEAUT32. 439]4917 * VarBstrCat [OLEAUT32.313] 4660 4918 */ 4661 4919 HRESULT WINAPI VarBstrCat(BSTR left, BSTR right, BSTR *out) 4662 4920 { 4663 4921 BSTR result; 4922 int size = 0; 4664 4923 4665 4924 TRACE("( %s %s %p )\n", debugstr_w(left), debugstr_w(right), out); 4666 4925 4667 if( (!left) || (!right) || (!out) ) 4668 return 0; 4669 4670 result = SysAllocStringLen(left, lstrlenW(left)+lstrlenW(right)); 4671 lstrcatW(result,right); 4672 4673 *out = result; 4674 4675 return 1; 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); 4929 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; 4676 4938 } 4677 4939 4678 4940 /********************************************************************** 4679 * VarCat [OLEAUT32. 441]4941 * VarCat [OLEAUT32.318] 4680 4942 */ 4681 4943 HRESULT WINAPI VarCat(LPVARIANT left, LPVARIANT right, LPVARIANT out) … … 4699 4961 return S_OK; 4700 4962 } 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 */ 4972 HRESULT 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 */ 5078 HRESULT 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 */ 5112 HRESULT 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 */ 5147 HRESULT 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 */ 5288 HRESULT 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 */ 5486 HRESULT 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 */ 5563 HRESULT 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), 5572 pcyOut->s.Hi, pcyOut->s.Lo); 5573 } 5574 return rc; 5575 }
Note:
See TracChangeset
for help on using the changeset viewer.