1 /* 2 * Low level variant functions 3 * 4 * Copyright 2003 Jon Griffiths 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #define COBJMACROS 22 #define NONAMELESSUNION 23 #define NONAMELESSSTRUCT 24 25 #include "wine/debug.h" 26 #include "wine/unicode.h" 27 #include "winbase.h" 28 #include "winuser.h" 29 #include "winnt.h" 30 #include "variant.h" 31 #include "resource.h" 32 33 WINE_DEFAULT_DEBUG_CHANNEL(variant); 34 35 extern HMODULE hProxyDll DECLSPEC_HIDDEN; 36 37 #define CY_MULTIPLIER 10000 /* 4 dp of precision */ 38 #define CY_MULTIPLIER_F 10000.0 39 #define CY_HALF (CY_MULTIPLIER/2) /* 0.5 */ 40 #define CY_HALF_F (CY_MULTIPLIER_F/2.0) 41 42 static const WCHAR szFloatFormatW[] = { '%','.','7','G','\0' }; 43 static const WCHAR szDoubleFormatW[] = { '%','.','1','5','G','\0' }; 44 45 /* Copy data from one variant to another. */ 46 static inline void VARIANT_CopyData(const VARIANT *srcVar, VARTYPE vt, void *pOut) 47 { 48 switch (vt) 49 { 50 case VT_I1: 51 case VT_UI1: memcpy(pOut, &V_UI1(srcVar), sizeof(BYTE)); break; 52 case VT_BOOL: 53 case VT_I2: 54 case VT_UI2: memcpy(pOut, &V_UI2(srcVar), sizeof(SHORT)); break; 55 case VT_R4: 56 case VT_INT: 57 case VT_I4: 58 case VT_UINT: 59 case VT_UI4: memcpy(pOut, &V_UI4(srcVar), sizeof (LONG)); break; 60 case VT_R8: 61 case VT_DATE: 62 case VT_CY: 63 case VT_I8: 64 case VT_UI8: memcpy(pOut, &V_UI8(srcVar), sizeof (LONG64)); break; 65 case VT_INT_PTR: memcpy(pOut, &V_INT_PTR(srcVar), sizeof (INT_PTR)); break; 66 case VT_DECIMAL: memcpy(pOut, &V_DECIMAL(srcVar), sizeof (DECIMAL)); break; 67 case VT_BSTR: memcpy(pOut, &V_BSTR(srcVar), sizeof(BSTR)); break; 68 default: 69 FIXME("VT_ type %d unhandled, please report!\n", vt); 70 } 71 } 72 73 /* Macro to inline conversion from a float or double to any integer type, 74 * rounding according to the 'dutch' convention. 75 */ 76 #define VARIANT_DutchRound(typ, value, res) do { \ 77 double whole = value < 0 ? ceil(value) : floor(value); \ 78 double fract = value - whole; \ 79 if (fract > 0.5) res = (typ)whole + (typ)1; \ 80 else if (fract == 0.5) { typ is_odd = (typ)whole & 1; res = whole + is_odd; } \ 81 else if (fract >= 0.0) res = (typ)whole; \ 82 else if (fract == -0.5) { typ is_odd = (typ)whole & 1; res = whole - is_odd; } \ 83 else if (fract > -0.5) res = (typ)whole; \ 84 else res = (typ)whole - (typ)1; \ 85 } while(0) 86 87 88 /* Coerce VT_BSTR to a numeric type */ 89 static HRESULT VARIANT_NumberFromBstr(OLECHAR* pStrIn, LCID lcid, ULONG ulFlags, 90 void* pOut, VARTYPE vt) 91 { 92 VARIANTARG dstVar; 93 HRESULT hRet; 94 NUMPARSE np; 95 BYTE rgb[1024]; 96 97 /* Use VarParseNumFromStr/VarNumFromParseNum as MSDN indicates */ 98 np.cDig = sizeof(rgb) / sizeof(BYTE); 99 np.dwInFlags = NUMPRS_STD; 100 101 hRet = VarParseNumFromStr(pStrIn, lcid, ulFlags, &np, rgb); 102 103 if (SUCCEEDED(hRet)) 104 { 105 /* 1 << vt gives us the VTBIT constant for the destination number type */ 106 hRet = VarNumFromParseNum(&np, rgb, 1 << vt, &dstVar); 107 if (SUCCEEDED(hRet)) 108 VARIANT_CopyData(&dstVar, vt, pOut); 109 } 110 return hRet; 111 } 112 113 /* Coerce VT_DISPATCH to another type */ 114 static HRESULT VARIANT_FromDisp(IDispatch* pdispIn, LCID lcid, void* pOut, 115 VARTYPE vt, DWORD dwFlags) 116 { 117 static DISPPARAMS emptyParams = { NULL, NULL, 0, 0 }; 118 VARIANTARG srcVar, dstVar; 119 HRESULT hRet; 120 121 if (!pdispIn) 122 return DISP_E_BADVARTYPE; 123 124 /* Get the default 'value' property from the IDispatch */ 125 VariantInit(&srcVar); 126 hRet = IDispatch_Invoke(pdispIn, DISPID_VALUE, &IID_NULL, lcid, DISPATCH_PROPERTYGET, 127 &emptyParams, &srcVar, NULL, NULL); 128 129 if (SUCCEEDED(hRet)) 130 { 131 /* Convert the property to the requested type */ 132 VariantInit(&dstVar); 133 hRet = VariantChangeTypeEx(&dstVar, &srcVar, lcid, dwFlags, vt); 134 VariantClear(&srcVar); 135 136 if (SUCCEEDED(hRet)) 137 VARIANT_CopyData(&dstVar, vt, pOut); 138 } 139 else 140 hRet = DISP_E_TYPEMISMATCH; 141 return hRet; 142 } 143 144 /* Inline return type */ 145 #define RETTYP static inline HRESULT 146 147 148 /* Simple compiler cast from one type to another */ 149 #define SIMPLE(dest, src, func) RETTYP _##func(src in, dest* out) { \ 150 *out = in; return S_OK; } 151 152 /* Compiler cast where input cannot be negative */ 153 #define NEGTST(dest, src, func) RETTYP _##func(src in, dest* out) { \ 154 if (in < 0) return DISP_E_OVERFLOW; *out = in; return S_OK; } 155 156 /* Compiler cast where input cannot be > some number */ 157 #define POSTST(dest, src, func, tst) RETTYP _##func(src in, dest* out) { \ 158 if (in > (dest)tst) return DISP_E_OVERFLOW; *out = in; return S_OK; } 159 160 /* Compiler cast where input cannot be < some number or >= some other number */ 161 #define BOTHTST(dest, src, func, lo, hi) RETTYP _##func(src in, dest* out) { \ 162 if (in < (dest)lo || in > hi) return DISP_E_OVERFLOW; *out = in; return S_OK; } 163 164 /* I1 */ 165 POSTST(signed char, BYTE, VarI1FromUI1, I1_MAX) 166 BOTHTST(signed char, SHORT, VarI1FromI2, I1_MIN, I1_MAX) 167 BOTHTST(signed char, LONG, VarI1FromI4, I1_MIN, I1_MAX) 168 SIMPLE(signed char, VARIANT_BOOL, VarI1FromBool) 169 POSTST(signed char, USHORT, VarI1FromUI2, I1_MAX) 170 POSTST(signed char, ULONG, VarI1FromUI4, I1_MAX) 171 BOTHTST(signed char, LONG64, VarI1FromI8, I1_MIN, I1_MAX) 172 POSTST(signed char, ULONG64, VarI1FromUI8, I1_MAX) 173 174 /* UI1 */ 175 BOTHTST(BYTE, SHORT, VarUI1FromI2, UI1_MIN, UI1_MAX) 176 SIMPLE(BYTE, VARIANT_BOOL, VarUI1FromBool) 177 NEGTST(BYTE, signed char, VarUI1FromI1) 178 POSTST(BYTE, USHORT, VarUI1FromUI2, UI1_MAX) 179 BOTHTST(BYTE, LONG, VarUI1FromI4, UI1_MIN, UI1_MAX) 180 POSTST(BYTE, ULONG, VarUI1FromUI4, UI1_MAX) 181 BOTHTST(BYTE, LONG64, VarUI1FromI8, UI1_MIN, UI1_MAX) 182 POSTST(BYTE, ULONG64, VarUI1FromUI8, UI1_MAX) 183 184 /* I2 */ 185 SIMPLE(SHORT, BYTE, VarI2FromUI1) 186 BOTHTST(SHORT, LONG, VarI2FromI4, I2_MIN, I2_MAX) 187 SIMPLE(SHORT, VARIANT_BOOL, VarI2FromBool) 188 SIMPLE(SHORT, signed char, VarI2FromI1) 189 POSTST(SHORT, USHORT, VarI2FromUI2, I2_MAX) 190 POSTST(SHORT, ULONG, VarI2FromUI4, I2_MAX) 191 BOTHTST(SHORT, LONG64, VarI2FromI8, I2_MIN, I2_MAX) 192 POSTST(SHORT, ULONG64, VarI2FromUI8, I2_MAX) 193 194 /* UI2 */ 195 SIMPLE(USHORT, BYTE, VarUI2FromUI1) 196 NEGTST(USHORT, SHORT, VarUI2FromI2) 197 BOTHTST(USHORT, LONG, VarUI2FromI4, UI2_MIN, UI2_MAX) 198 SIMPLE(USHORT, VARIANT_BOOL, VarUI2FromBool) 199 NEGTST(USHORT, signed char, VarUI2FromI1) 200 POSTST(USHORT, ULONG, VarUI2FromUI4, UI2_MAX) 201 BOTHTST(USHORT, LONG64, VarUI2FromI8, UI2_MIN, UI2_MAX) 202 POSTST(USHORT, ULONG64, VarUI2FromUI8, UI2_MAX) 203 204 /* I4 */ 205 SIMPLE(LONG, BYTE, VarI4FromUI1) 206 SIMPLE(LONG, SHORT, VarI4FromI2) 207 SIMPLE(LONG, VARIANT_BOOL, VarI4FromBool) 208 SIMPLE(LONG, signed char, VarI4FromI1) 209 SIMPLE(LONG, USHORT, VarI4FromUI2) 210 POSTST(LONG, ULONG, VarI4FromUI4, I4_MAX) 211 BOTHTST(LONG, LONG64, VarI4FromI8, I4_MIN, I4_MAX) 212 POSTST(LONG, ULONG64, VarI4FromUI8, I4_MAX) 213 214 /* UI4 */ 215 SIMPLE(ULONG, BYTE, VarUI4FromUI1) 216 NEGTST(ULONG, SHORT, VarUI4FromI2) 217 NEGTST(ULONG, LONG, VarUI4FromI4) 218 SIMPLE(ULONG, VARIANT_BOOL, VarUI4FromBool) 219 NEGTST(ULONG, signed char, VarUI4FromI1) 220 SIMPLE(ULONG, USHORT, VarUI4FromUI2) 221 BOTHTST(ULONG, LONG64, VarUI4FromI8, UI4_MIN, UI4_MAX) 222 POSTST(ULONG, ULONG64, VarUI4FromUI8, UI4_MAX) 223 224 /* I8 */ 225 SIMPLE(LONG64, BYTE, VarI8FromUI1) 226 SIMPLE(LONG64, SHORT, VarI8FromI2) 227 SIMPLE(LONG64, signed char, VarI8FromI1) 228 SIMPLE(LONG64, USHORT, VarI8FromUI2) 229 SIMPLE(LONG64, ULONG, VarI8FromUI4) 230 POSTST(LONG64, ULONG64, VarI8FromUI8, I8_MAX) 231 232 /* UI8 */ 233 SIMPLE(ULONG64, BYTE, VarUI8FromUI1) 234 NEGTST(ULONG64, SHORT, VarUI8FromI2) 235 NEGTST(ULONG64, signed char, VarUI8FromI1) 236 SIMPLE(ULONG64, USHORT, VarUI8FromUI2) 237 SIMPLE(ULONG64, ULONG, VarUI8FromUI4) 238 NEGTST(ULONG64, LONG64, VarUI8FromI8) 239 240 /* R4 (float) */ 241 SIMPLE(float, BYTE, VarR4FromUI1) 242 SIMPLE(float, SHORT, VarR4FromI2) 243 SIMPLE(float, signed char, VarR4FromI1) 244 SIMPLE(float, USHORT, VarR4FromUI2) 245 SIMPLE(float, LONG, VarR4FromI4) 246 SIMPLE(float, ULONG, VarR4FromUI4) 247 SIMPLE(float, LONG64, VarR4FromI8) 248 SIMPLE(float, ULONG64, VarR4FromUI8) 249 250 /* R8 (double) */ 251 SIMPLE(double, BYTE, VarR8FromUI1) 252 SIMPLE(double, SHORT, VarR8FromI2) 253 SIMPLE(double, float, VarR8FromR4) 254 RETTYP _VarR8FromCy(CY i, double* o) { *o = (double)i.int64 / CY_MULTIPLIER_F; return S_OK; } 255 SIMPLE(double, DATE, VarR8FromDate) 256 SIMPLE(double, signed char, VarR8FromI1) 257 SIMPLE(double, USHORT, VarR8FromUI2) 258 SIMPLE(double, LONG, VarR8FromI4) 259 SIMPLE(double, ULONG, VarR8FromUI4) 260 SIMPLE(double, LONG64, VarR8FromI8) 261 SIMPLE(double, ULONG64, VarR8FromUI8) 262 263 264 /* I1 265 */ 266 267 /************************************************************************ 268 * VarI1FromUI1 (OLEAUT32.244) 269 * 270 * Convert a VT_UI1 to a VT_I1. 271 * 272 * PARAMS 273 * bIn [I] Source 274 * pcOut [O] Destination 275 * 276 * RETURNS 277 * Success: S_OK. 278 * Failure: E_INVALIDARG, if the source value is invalid 279 * DISP_E_OVERFLOW, if the value will not fit in the destination 280 */ 281 HRESULT WINAPI VarI1FromUI1(BYTE bIn, signed char* pcOut) 282 { 283 return _VarI1FromUI1(bIn, pcOut); 284 } 285 286 /************************************************************************ 287 * VarI1FromI2 (OLEAUT32.245) 288 * 289 * Convert a VT_I2 to a VT_I1. 290 * 291 * PARAMS 292 * sIn [I] Source 293 * pcOut [O] Destination 294 * 295 * RETURNS 296 * Success: S_OK. 297 * Failure: E_INVALIDARG, if the source value is invalid 298 * DISP_E_OVERFLOW, if the value will not fit in the destination 299 */ 300 HRESULT WINAPI VarI1FromI2(SHORT sIn, signed char* pcOut) 301 { 302 return _VarI1FromI2(sIn, pcOut); 303 } 304 305 /************************************************************************ 306 * VarI1FromI4 (OLEAUT32.246) 307 * 308 * Convert a VT_I4 to a VT_I1. 309 * 310 * PARAMS 311 * iIn [I] Source 312 * pcOut [O] Destination 313 * 314 * RETURNS 315 * Success: S_OK. 316 * Failure: E_INVALIDARG, if the source value is invalid 317 * DISP_E_OVERFLOW, if the value will not fit in the destination 318 */ 319 HRESULT WINAPI VarI1FromI4(LONG iIn, signed char* pcOut) 320 { 321 return _VarI1FromI4(iIn, pcOut); 322 } 323 324 /************************************************************************ 325 * VarI1FromR4 (OLEAUT32.247) 326 * 327 * Convert a VT_R4 to a VT_I1. 328 * 329 * PARAMS 330 * fltIn [I] Source 331 * pcOut [O] Destination 332 * 333 * RETURNS 334 * Success: S_OK. 335 * Failure: E_INVALIDARG, if the source value is invalid 336 * DISP_E_OVERFLOW, if the value will not fit in the destination 337 */ 338 HRESULT WINAPI VarI1FromR4(FLOAT fltIn, signed char* pcOut) 339 { 340 return VarI1FromR8(fltIn, pcOut); 341 } 342 343 /************************************************************************ 344 * VarI1FromR8 (OLEAUT32.248) 345 * 346 * Convert a VT_R8 to a VT_I1. 347 * 348 * PARAMS 349 * dblIn [I] Source 350 * pcOut [O] Destination 351 * 352 * RETURNS 353 * Success: S_OK. 354 * Failure: E_INVALIDARG, if the source value is invalid 355 * DISP_E_OVERFLOW, if the value will not fit in the destination 356 * 357 * NOTES 358 * See VarI8FromR8() for details concerning rounding. 359 */ 360 HRESULT WINAPI VarI1FromR8(double dblIn, signed char* pcOut) 361 { 362 if (dblIn < I1_MIN - 0.5 || dblIn >= I1_MAX + 0.5) 363 return DISP_E_OVERFLOW; 364 VARIANT_DutchRound(CHAR, dblIn, *pcOut); 365 return S_OK; 366 } 367 368 /************************************************************************ 369 * VarI1FromDate (OLEAUT32.249) 370 * 371 * Convert a VT_DATE to a VT_I1. 372 * 373 * PARAMS 374 * dateIn [I] Source 375 * pcOut [O] Destination 376 * 377 * RETURNS 378 * Success: S_OK. 379 * Failure: E_INVALIDARG, if the source value is invalid 380 * DISP_E_OVERFLOW, if the value will not fit in the destination 381 */ 382 HRESULT WINAPI VarI1FromDate(DATE dateIn, signed char* pcOut) 383 { 384 return VarI1FromR8(dateIn, pcOut); 385 } 386 387 /************************************************************************ 388 * VarI1FromCy (OLEAUT32.250) 389 * 390 * Convert a VT_CY to a VT_I1. 391 * 392 * PARAMS 393 * cyIn [I] Source 394 * pcOut [O] Destination 395 * 396 * RETURNS 397 * Success: S_OK. 398 * Failure: E_INVALIDARG, if the source value is invalid 399 * DISP_E_OVERFLOW, if the value will not fit in the destination 400 */ 401 HRESULT WINAPI VarI1FromCy(CY cyIn, signed char* pcOut) 402 { 403 LONG i = I1_MAX + 1; 404 405 VarI4FromCy(cyIn, &i); 406 return _VarI1FromI4(i, pcOut); 407 } 408 409 /************************************************************************ 410 * VarI1FromStr (OLEAUT32.251) 411 * 412 * Convert a VT_BSTR to a VT_I1. 413 * 414 * PARAMS 415 * strIn [I] Source 416 * lcid [I] LCID for the conversion 417 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 418 * pcOut [O] Destination 419 * 420 * RETURNS 421 * Success: S_OK. 422 * Failure: E_INVALIDARG, if the source value is invalid 423 * DISP_E_OVERFLOW, if the value will not fit in the destination 424 * DISP_E_TYPEMISMATCH, if the type cannot be converted 425 */ 426 HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, signed char* pcOut) 427 { 428 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pcOut, VT_I1); 429 } 430 431 /************************************************************************ 432 * VarI1FromDisp (OLEAUT32.252) 433 * 434 * Convert a VT_DISPATCH to a VT_I1. 435 * 436 * PARAMS 437 * pdispIn [I] Source 438 * lcid [I] LCID for conversion 439 * pcOut [O] Destination 440 * 441 * RETURNS 442 * Success: S_OK. 443 * Failure: E_INVALIDARG, if the source value is invalid 444 * DISP_E_OVERFLOW, if the value will not fit in the destination 445 * DISP_E_TYPEMISMATCH, if the type cannot be converted 446 */ 447 HRESULT WINAPI VarI1FromDisp(IDispatch* pdispIn, LCID lcid, signed char* pcOut) 448 { 449 return VARIANT_FromDisp(pdispIn, lcid, pcOut, VT_I1, 0); 450 } 451 452 /************************************************************************ 453 * VarI1FromBool (OLEAUT32.253) 454 * 455 * Convert a VT_BOOL to a VT_I1. 456 * 457 * PARAMS 458 * boolIn [I] Source 459 * pcOut [O] Destination 460 * 461 * RETURNS 462 * S_OK. 463 */ 464 HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, signed char* pcOut) 465 { 466 return _VarI1FromBool(boolIn, pcOut); 467 } 468 469 /************************************************************************ 470 * VarI1FromUI2 (OLEAUT32.254) 471 * 472 * Convert a VT_UI2 to a VT_I1. 473 * 474 * PARAMS 475 * usIn [I] Source 476 * pcOut [O] Destination 477 * 478 * RETURNS 479 * Success: S_OK. 480 * Failure: E_INVALIDARG, if the source value is invalid 481 * DISP_E_OVERFLOW, if the value will not fit in the destination 482 */ 483 HRESULT WINAPI VarI1FromUI2(USHORT usIn, signed char* pcOut) 484 { 485 return _VarI1FromUI2(usIn, pcOut); 486 } 487 488 /************************************************************************ 489 * VarI1FromUI4 (OLEAUT32.255) 490 * 491 * Convert a VT_UI4 to a VT_I1. 492 * 493 * PARAMS 494 * ulIn [I] Source 495 * pcOut [O] Destination 496 * 497 * RETURNS 498 * Success: S_OK. 499 * Failure: E_INVALIDARG, if the source value is invalid 500 * DISP_E_OVERFLOW, if the value will not fit in the destination 501 * DISP_E_TYPEMISMATCH, if the type cannot be converted 502 */ 503 HRESULT WINAPI VarI1FromUI4(ULONG ulIn, signed char* pcOut) 504 { 505 return _VarI1FromUI4(ulIn, pcOut); 506 } 507 508 /************************************************************************ 509 * VarI1FromDec (OLEAUT32.256) 510 * 511 * Convert a VT_DECIMAL to a VT_I1. 512 * 513 * PARAMS 514 * pDecIn [I] Source 515 * pcOut [O] Destination 516 * 517 * RETURNS 518 * Success: S_OK. 519 * Failure: E_INVALIDARG, if the source value is invalid 520 * DISP_E_OVERFLOW, if the value will not fit in the destination 521 */ 522 HRESULT WINAPI VarI1FromDec(DECIMAL *pdecIn, signed char* pcOut) 523 { 524 LONG64 i64; 525 HRESULT hRet; 526 527 hRet = VarI8FromDec(pdecIn, &i64); 528 529 if (SUCCEEDED(hRet)) 530 hRet = _VarI1FromI8(i64, pcOut); 531 return hRet; 532 } 533 534 /************************************************************************ 535 * VarI1FromI8 (OLEAUT32.376) 536 * 537 * Convert a VT_I8 to a VT_I1. 538 * 539 * PARAMS 540 * llIn [I] Source 541 * pcOut [O] Destination 542 * 543 * RETURNS 544 * Success: S_OK. 545 * Failure: E_INVALIDARG, if the source value is invalid 546 * DISP_E_OVERFLOW, if the value will not fit in the destination 547 */ 548 HRESULT WINAPI VarI1FromI8(LONG64 llIn, signed char* pcOut) 549 { 550 return _VarI1FromI8(llIn, pcOut); 551 } 552 553 /************************************************************************ 554 * VarI1FromUI8 (OLEAUT32.377) 555 * 556 * Convert a VT_UI8 to a VT_I1. 557 * 558 * PARAMS 559 * ullIn [I] Source 560 * pcOut [O] Destination 561 * 562 * RETURNS 563 * Success: S_OK. 564 * Failure: E_INVALIDARG, if the source value is invalid 565 * DISP_E_OVERFLOW, if the value will not fit in the destination 566 */ 567 HRESULT WINAPI VarI1FromUI8(ULONG64 ullIn, signed char* pcOut) 568 { 569 return _VarI1FromUI8(ullIn, pcOut); 570 } 571 572 /* UI1 573 */ 574 575 /************************************************************************ 576 * VarUI1FromI2 (OLEAUT32.130) 577 * 578 * Convert a VT_I2 to a VT_UI1. 579 * 580 * PARAMS 581 * sIn [I] Source 582 * pbOut [O] Destination 583 * 584 * RETURNS 585 * Success: S_OK. 586 * Failure: E_INVALIDARG, if the source value is invalid 587 * DISP_E_OVERFLOW, if the value will not fit in the destination 588 */ 589 HRESULT WINAPI VarUI1FromI2(SHORT sIn, BYTE* pbOut) 590 { 591 return _VarUI1FromI2(sIn, pbOut); 592 } 593 594 /************************************************************************ 595 * VarUI1FromI4 (OLEAUT32.131) 596 * 597 * Convert a VT_I4 to a VT_UI1. 598 * 599 * PARAMS 600 * iIn [I] Source 601 * pbOut [O] Destination 602 * 603 * RETURNS 604 * Success: S_OK. 605 * Failure: E_INVALIDARG, if the source value is invalid 606 * DISP_E_OVERFLOW, if the value will not fit in the destination 607 */ 608 HRESULT WINAPI VarUI1FromI4(LONG iIn, BYTE* pbOut) 609 { 610 return _VarUI1FromI4(iIn, pbOut); 611 } 612 613 /************************************************************************ 614 * VarUI1FromR4 (OLEAUT32.132) 615 * 616 * Convert a VT_R4 to a VT_UI1. 617 * 618 * PARAMS 619 * fltIn [I] Source 620 * pbOut [O] Destination 621 * 622 * RETURNS 623 * Success: S_OK. 624 * Failure: E_INVALIDARG, if the source value is invalid 625 * DISP_E_OVERFLOW, if the value will not fit in the destination 626 * DISP_E_TYPEMISMATCH, if the type cannot be converted 627 */ 628 HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut) 629 { 630 return VarUI1FromR8(fltIn, pbOut); 631 } 632 633 /************************************************************************ 634 * VarUI1FromR8 (OLEAUT32.133) 635 * 636 * Convert a VT_R8 to a VT_UI1. 637 * 638 * PARAMS 639 * dblIn [I] Source 640 * pbOut [O] Destination 641 * 642 * RETURNS 643 * Success: S_OK. 644 * Failure: E_INVALIDARG, if the source value is invalid 645 * DISP_E_OVERFLOW, if the value will not fit in the destination 646 * 647 * NOTES 648 * See VarI8FromR8() for details concerning rounding. 649 */ 650 HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut) 651 { 652 if (dblIn < -0.5 || dblIn >= UI1_MAX + 0.5) 653 return DISP_E_OVERFLOW; 654 VARIANT_DutchRound(BYTE, dblIn, *pbOut); 655 return S_OK; 656 } 657 658 /************************************************************************ 659 * VarUI1FromCy (OLEAUT32.134) 660 * 661 * Convert a VT_CY to a VT_UI1. 662 * 663 * PARAMS 664 * cyIn [I] Source 665 * pbOut [O] Destination 666 * 667 * RETURNS 668 * Success: S_OK. 669 * Failure: E_INVALIDARG, if the source value is invalid 670 * DISP_E_OVERFLOW, if the value will not fit in the destination 671 * 672 * NOTES 673 * Negative values >= -5000 will be converted to 0. 674 */ 675 HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut) 676 { 677 ULONG i = UI1_MAX + 1; 678 679 VarUI4FromCy(cyIn, &i); 680 return _VarUI1FromUI4(i, pbOut); 681 } 682 683 /************************************************************************ 684 * VarUI1FromDate (OLEAUT32.135) 685 * 686 * Convert a VT_DATE to a VT_UI1. 687 * 688 * PARAMS 689 * dateIn [I] Source 690 * pbOut [O] Destination 691 * 692 * RETURNS 693 * Success: S_OK. 694 * Failure: E_INVALIDARG, if the source value is invalid 695 * DISP_E_OVERFLOW, if the value will not fit in the destination 696 */ 697 HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut) 698 { 699 return VarUI1FromR8(dateIn, pbOut); 700 } 701 702 /************************************************************************ 703 * VarUI1FromStr (OLEAUT32.136) 704 * 705 * Convert a VT_BSTR to a VT_UI1. 706 * 707 * PARAMS 708 * strIn [I] Source 709 * lcid [I] LCID for the conversion 710 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 711 * pbOut [O] Destination 712 * 713 * RETURNS 714 * Success: S_OK. 715 * Failure: E_INVALIDARG, if the source value is invalid 716 * DISP_E_OVERFLOW, if the value will not fit in the destination 717 * DISP_E_TYPEMISMATCH, if the type cannot be converted 718 */ 719 HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut) 720 { 721 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pbOut, VT_UI1); 722 } 723 724 /************************************************************************ 725 * VarUI1FromDisp (OLEAUT32.137) 726 * 727 * Convert a VT_DISPATCH to a VT_UI1. 728 * 729 * PARAMS 730 * pdispIn [I] Source 731 * lcid [I] LCID for conversion 732 * pbOut [O] Destination 733 * 734 * RETURNS 735 * Success: S_OK. 736 * Failure: E_INVALIDARG, if the source value is invalid 737 * DISP_E_OVERFLOW, if the value will not fit in the destination 738 * DISP_E_TYPEMISMATCH, if the type cannot be converted 739 */ 740 HRESULT WINAPI VarUI1FromDisp(IDispatch* pdispIn, LCID lcid, BYTE* pbOut) 741 { 742 return VARIANT_FromDisp(pdispIn, lcid, pbOut, VT_UI1, 0); 743 } 744 745 /************************************************************************ 746 * VarUI1FromBool (OLEAUT32.138) 747 * 748 * Convert a VT_BOOL to a VT_UI1. 749 * 750 * PARAMS 751 * boolIn [I] Source 752 * pbOut [O] Destination 753 * 754 * RETURNS 755 * S_OK. 756 */ 757 HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut) 758 { 759 return _VarUI1FromBool(boolIn, pbOut); 760 } 761 762 /************************************************************************ 763 * VarUI1FromI1 (OLEAUT32.237) 764 * 765 * Convert a VT_I1 to a VT_UI1. 766 * 767 * PARAMS 768 * cIn [I] Source 769 * pbOut [O] Destination 770 * 771 * RETURNS 772 * Success: S_OK. 773 * Failure: E_INVALIDARG, if the source value is invalid 774 * DISP_E_OVERFLOW, if the value will not fit in the destination 775 */ 776 HRESULT WINAPI VarUI1FromI1(signed char cIn, BYTE* pbOut) 777 { 778 return _VarUI1FromI1(cIn, pbOut); 779 } 780 781 /************************************************************************ 782 * VarUI1FromUI2 (OLEAUT32.238) 783 * 784 * Convert a VT_UI2 to a VT_UI1. 785 * 786 * PARAMS 787 * usIn [I] Source 788 * pbOut [O] Destination 789 * 790 * RETURNS 791 * Success: S_OK. 792 * Failure: E_INVALIDARG, if the source value is invalid 793 * DISP_E_OVERFLOW, if the value will not fit in the destination 794 */ 795 HRESULT WINAPI VarUI1FromUI2(USHORT usIn, BYTE* pbOut) 796 { 797 return _VarUI1FromUI2(usIn, pbOut); 798 } 799 800 /************************************************************************ 801 * VarUI1FromUI4 (OLEAUT32.239) 802 * 803 * Convert a VT_UI4 to a VT_UI1. 804 * 805 * PARAMS 806 * ulIn [I] Source 807 * pbOut [O] Destination 808 * 809 * RETURNS 810 * Success: S_OK. 811 * Failure: E_INVALIDARG, if the source value is invalid 812 * DISP_E_OVERFLOW, if the value will not fit in the destination 813 */ 814 HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut) 815 { 816 return _VarUI1FromUI4(ulIn, pbOut); 817 } 818 819 /************************************************************************ 820 * VarUI1FromDec (OLEAUT32.240) 821 * 822 * Convert a VT_DECIMAL to a VT_UI1. 823 * 824 * PARAMS 825 * pDecIn [I] Source 826 * pbOut [O] Destination 827 * 828 * RETURNS 829 * Success: S_OK. 830 * Failure: E_INVALIDARG, if the source value is invalid 831 * DISP_E_OVERFLOW, if the value will not fit in the destination 832 */ 833 HRESULT WINAPI VarUI1FromDec(DECIMAL *pdecIn, BYTE* pbOut) 834 { 835 LONG64 i64; 836 HRESULT hRet; 837 838 hRet = VarI8FromDec(pdecIn, &i64); 839 840 if (SUCCEEDED(hRet)) 841 hRet = _VarUI1FromI8(i64, pbOut); 842 return hRet; 843 } 844 845 /************************************************************************ 846 * VarUI1FromI8 (OLEAUT32.372) 847 * 848 * Convert a VT_I8 to a VT_UI1. 849 * 850 * PARAMS 851 * llIn [I] Source 852 * pbOut [O] Destination 853 * 854 * RETURNS 855 * Success: S_OK. 856 * Failure: E_INVALIDARG, if the source value is invalid 857 * DISP_E_OVERFLOW, if the value will not fit in the destination 858 */ 859 HRESULT WINAPI VarUI1FromI8(LONG64 llIn, BYTE* pbOut) 860 { 861 return _VarUI1FromI8(llIn, pbOut); 862 } 863 864 /************************************************************************ 865 * VarUI1FromUI8 (OLEAUT32.373) 866 * 867 * Convert a VT_UI8 to a VT_UI1. 868 * 869 * PARAMS 870 * ullIn [I] Source 871 * pbOut [O] Destination 872 * 873 * RETURNS 874 * Success: S_OK. 875 * Failure: E_INVALIDARG, if the source value is invalid 876 * DISP_E_OVERFLOW, if the value will not fit in the destination 877 */ 878 HRESULT WINAPI VarUI1FromUI8(ULONG64 ullIn, BYTE* pbOut) 879 { 880 return _VarUI1FromUI8(ullIn, pbOut); 881 } 882 883 884 /* I2 885 */ 886 887 /************************************************************************ 888 * VarI2FromUI1 (OLEAUT32.48) 889 * 890 * Convert a VT_UI2 to a VT_I2. 891 * 892 * PARAMS 893 * bIn [I] Source 894 * psOut [O] Destination 895 * 896 * RETURNS 897 * S_OK. 898 */ 899 HRESULT WINAPI VarI2FromUI1(BYTE bIn, SHORT* psOut) 900 { 901 return _VarI2FromUI1(bIn, psOut); 902 } 903 904 /************************************************************************ 905 * VarI2FromI4 (OLEAUT32.49) 906 * 907 * Convert a VT_I4 to a VT_I2. 908 * 909 * PARAMS 910 * iIn [I] Source 911 * psOut [O] Destination 912 * 913 * RETURNS 914 * Success: S_OK. 915 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 916 */ 917 HRESULT WINAPI VarI2FromI4(LONG iIn, SHORT* psOut) 918 { 919 return _VarI2FromI4(iIn, psOut); 920 } 921 922 /************************************************************************ 923 * VarI2FromR4 (OLEAUT32.50) 924 * 925 * Convert a VT_R4 to a VT_I2. 926 * 927 * PARAMS 928 * fltIn [I] Source 929 * psOut [O] Destination 930 * 931 * RETURNS 932 * Success: S_OK. 933 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 934 */ 935 HRESULT WINAPI VarI2FromR4(FLOAT fltIn, SHORT* psOut) 936 { 937 return VarI2FromR8(fltIn, psOut); 938 } 939 940 /************************************************************************ 941 * VarI2FromR8 (OLEAUT32.51) 942 * 943 * Convert a VT_R8 to a VT_I2. 944 * 945 * PARAMS 946 * dblIn [I] Source 947 * psOut [O] Destination 948 * 949 * RETURNS 950 * Success: S_OK. 951 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 952 * 953 * NOTES 954 * See VarI8FromR8() for details concerning rounding. 955 */ 956 HRESULT WINAPI VarI2FromR8(double dblIn, SHORT* psOut) 957 { 958 if (dblIn < I2_MIN - 0.5 || dblIn >= I2_MAX + 0.5) 959 return DISP_E_OVERFLOW; 960 VARIANT_DutchRound(SHORT, dblIn, *psOut); 961 return S_OK; 962 } 963 964 /************************************************************************ 965 * VarI2FromCy (OLEAUT32.52) 966 * 967 * Convert a VT_CY to a VT_I2. 968 * 969 * PARAMS 970 * cyIn [I] Source 971 * psOut [O] Destination 972 * 973 * RETURNS 974 * Success: S_OK. 975 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 976 */ 977 HRESULT WINAPI VarI2FromCy(CY cyIn, SHORT* psOut) 978 { 979 LONG i = I2_MAX + 1; 980 981 VarI4FromCy(cyIn, &i); 982 return _VarI2FromI4(i, psOut); 983 } 984 985 /************************************************************************ 986 * VarI2FromDate (OLEAUT32.53) 987 * 988 * Convert a VT_DATE to a VT_I2. 989 * 990 * PARAMS 991 * dateIn [I] Source 992 * psOut [O] Destination 993 * 994 * RETURNS 995 * Success: S_OK. 996 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 997 */ 998 HRESULT WINAPI VarI2FromDate(DATE dateIn, SHORT* psOut) 999 { 1000 return VarI2FromR8(dateIn, psOut); 1001 } 1002 1003 /************************************************************************ 1004 * VarI2FromStr (OLEAUT32.54) 1005 * 1006 * Convert a VT_BSTR to a VT_I2. 1007 * 1008 * PARAMS 1009 * strIn [I] Source 1010 * lcid [I] LCID for the conversion 1011 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 1012 * psOut [O] Destination 1013 * 1014 * RETURNS 1015 * Success: S_OK. 1016 * Failure: E_INVALIDARG, if any parameter is invalid 1017 * DISP_E_OVERFLOW, if the value will not fit in the destination 1018 * DISP_E_TYPEMISMATCH, if the type cannot be converted 1019 */ 1020 HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, SHORT* psOut) 1021 { 1022 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, psOut, VT_I2); 1023 } 1024 1025 /************************************************************************ 1026 * VarI2FromDisp (OLEAUT32.55) 1027 * 1028 * Convert a VT_DISPATCH to a VT_I2. 1029 * 1030 * PARAMS 1031 * pdispIn [I] Source 1032 * lcid [I] LCID for conversion 1033 * psOut [O] Destination 1034 * 1035 * RETURNS 1036 * Success: S_OK. 1037 * Failure: E_INVALIDARG, if pdispIn is invalid, 1038 * DISP_E_OVERFLOW, if the value will not fit in the destination, 1039 * DISP_E_TYPEMISMATCH, if the type cannot be converted 1040 */ 1041 HRESULT WINAPI VarI2FromDisp(IDispatch* pdispIn, LCID lcid, SHORT* psOut) 1042 { 1043 return VARIANT_FromDisp(pdispIn, lcid, psOut, VT_I2, 0); 1044 } 1045 1046 /************************************************************************ 1047 * VarI2FromBool (OLEAUT32.56) 1048 * 1049 * Convert a VT_BOOL to a VT_I2. 1050 * 1051 * PARAMS 1052 * boolIn [I] Source 1053 * psOut [O] Destination 1054 * 1055 * RETURNS 1056 * S_OK. 1057 */ 1058 HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, SHORT* psOut) 1059 { 1060 return _VarI2FromBool(boolIn, psOut); 1061 } 1062 1063 /************************************************************************ 1064 * VarI2FromI1 (OLEAUT32.205) 1065 * 1066 * Convert a VT_I1 to a VT_I2. 1067 * 1068 * PARAMS 1069 * cIn [I] Source 1070 * psOut [O] Destination 1071 * 1072 * RETURNS 1073 * S_OK. 1074 */ 1075 HRESULT WINAPI VarI2FromI1(signed char cIn, SHORT* psOut) 1076 { 1077 return _VarI2FromI1(cIn, psOut); 1078 } 1079 1080 /************************************************************************ 1081 * VarI2FromUI2 (OLEAUT32.206) 1082 * 1083 * Convert a VT_UI2 to a VT_I2. 1084 * 1085 * PARAMS 1086 * usIn [I] Source 1087 * psOut [O] Destination 1088 * 1089 * RETURNS 1090 * Success: S_OK. 1091 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 1092 */ 1093 HRESULT WINAPI VarI2FromUI2(USHORT usIn, SHORT* psOut) 1094 { 1095 return _VarI2FromUI2(usIn, psOut); 1096 } 1097 1098 /************************************************************************ 1099 * VarI2FromUI4 (OLEAUT32.207) 1100 * 1101 * Convert a VT_UI4 to a VT_I2. 1102 * 1103 * PARAMS 1104 * ulIn [I] Source 1105 * psOut [O] Destination 1106 * 1107 * RETURNS 1108 * Success: S_OK. 1109 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 1110 */ 1111 HRESULT WINAPI VarI2FromUI4(ULONG ulIn, SHORT* psOut) 1112 { 1113 return _VarI2FromUI4(ulIn, psOut); 1114 } 1115 1116 /************************************************************************ 1117 * VarI2FromDec (OLEAUT32.208) 1118 * 1119 * Convert a VT_DECIMAL to a VT_I2. 1120 * 1121 * PARAMS 1122 * pDecIn [I] Source 1123 * psOut [O] Destination 1124 * 1125 * RETURNS 1126 * Success: S_OK. 1127 * Failure: E_INVALIDARG, if the source value is invalid 1128 * DISP_E_OVERFLOW, if the value will not fit in the destination 1129 */ 1130 HRESULT WINAPI VarI2FromDec(DECIMAL *pdecIn, SHORT* psOut) 1131 { 1132 LONG64 i64; 1133 HRESULT hRet; 1134 1135 hRet = VarI8FromDec(pdecIn, &i64); 1136 1137 if (SUCCEEDED(hRet)) 1138 hRet = _VarI2FromI8(i64, psOut); 1139 return hRet; 1140 } 1141 1142 /************************************************************************ 1143 * VarI2FromI8 (OLEAUT32.346) 1144 * 1145 * Convert a VT_I8 to a VT_I2. 1146 * 1147 * PARAMS 1148 * llIn [I] Source 1149 * psOut [O] Destination 1150 * 1151 * RETURNS 1152 * Success: S_OK. 1153 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 1154 */ 1155 HRESULT WINAPI VarI2FromI8(LONG64 llIn, SHORT* psOut) 1156 { 1157 return _VarI2FromI8(llIn, psOut); 1158 } 1159 1160 /************************************************************************ 1161 * VarI2FromUI8 (OLEAUT32.347) 1162 * 1163 * Convert a VT_UI8 to a VT_I2. 1164 * 1165 * PARAMS 1166 * ullIn [I] Source 1167 * psOut [O] Destination 1168 * 1169 * RETURNS 1170 * Success: S_OK. 1171 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 1172 */ 1173 HRESULT WINAPI VarI2FromUI8(ULONG64 ullIn, SHORT* psOut) 1174 { 1175 return _VarI2FromUI8(ullIn, psOut); 1176 } 1177 1178 /* UI2 1179 */ 1180 1181 /************************************************************************ 1182 * VarUI2FromUI1 (OLEAUT32.257) 1183 * 1184 * Convert a VT_UI1 to a VT_UI2. 1185 * 1186 * PARAMS 1187 * bIn [I] Source 1188 * pusOut [O] Destination 1189 * 1190 * RETURNS 1191 * S_OK. 1192 */ 1193 HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* pusOut) 1194 { 1195 return _VarUI2FromUI1(bIn, pusOut); 1196 } 1197 1198 /************************************************************************ 1199 * VarUI2FromI2 (OLEAUT32.258) 1200 * 1201 * Convert a VT_I2 to a VT_UI2. 1202 * 1203 * PARAMS 1204 * sIn [I] Source 1205 * pusOut [O] Destination 1206 * 1207 * RETURNS 1208 * Success: S_OK. 1209 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 1210 */ 1211 HRESULT WINAPI VarUI2FromI2(SHORT sIn, USHORT* pusOut) 1212 { 1213 return _VarUI2FromI2(sIn, pusOut); 1214 } 1215 1216 /************************************************************************ 1217 * VarUI2FromI4 (OLEAUT32.259) 1218 * 1219 * Convert a VT_I4 to a VT_UI2. 1220 * 1221 * PARAMS 1222 * iIn [I] Source 1223 * pusOut [O] Destination 1224 * 1225 * RETURNS 1226 * Success: S_OK. 1227 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 1228 */ 1229 HRESULT WINAPI VarUI2FromI4(LONG iIn, USHORT* pusOut) 1230 { 1231 return _VarUI2FromI4(iIn, pusOut); 1232 } 1233 1234 /************************************************************************ 1235 * VarUI2FromR4 (OLEAUT32.260) 1236 * 1237 * Convert a VT_R4 to a VT_UI2. 1238 * 1239 * PARAMS 1240 * fltIn [I] Source 1241 * pusOut [O] Destination 1242 * 1243 * RETURNS 1244 * Success: S_OK. 1245 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 1246 */ 1247 HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* pusOut) 1248 { 1249 return VarUI2FromR8(fltIn, pusOut); 1250 } 1251 1252 /************************************************************************ 1253 * VarUI2FromR8 (OLEAUT32.261) 1254 * 1255 * Convert a VT_R8 to a VT_UI2. 1256 * 1257 * PARAMS 1258 * dblIn [I] Source 1259 * pusOut [O] Destination 1260 * 1261 * RETURNS 1262 * Success: S_OK. 1263 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 1264 * 1265 * NOTES 1266 * See VarI8FromR8() for details concerning rounding. 1267 */ 1268 HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* pusOut) 1269 { 1270 if (dblIn < -0.5 || dblIn >= UI2_MAX + 0.5) 1271 return DISP_E_OVERFLOW; 1272 VARIANT_DutchRound(USHORT, dblIn, *pusOut); 1273 return S_OK; 1274 } 1275 1276 /************************************************************************ 1277 * VarUI2FromDate (OLEAUT32.262) 1278 * 1279 * Convert a VT_DATE to a VT_UI2. 1280 * 1281 * PARAMS 1282 * dateIn [I] Source 1283 * pusOut [O] Destination 1284 * 1285 * RETURNS 1286 * Success: S_OK. 1287 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 1288 */ 1289 HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* pusOut) 1290 { 1291 return VarUI2FromR8(dateIn, pusOut); 1292 } 1293 1294 /************************************************************************ 1295 * VarUI2FromCy (OLEAUT32.263) 1296 * 1297 * Convert a VT_CY to a VT_UI2. 1298 * 1299 * PARAMS 1300 * cyIn [I] Source 1301 * pusOut [O] Destination 1302 * 1303 * RETURNS 1304 * Success: S_OK. 1305 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 1306 * 1307 * NOTES 1308 * Negative values >= -5000 will be converted to 0. 1309 */ 1310 HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut) 1311 { 1312 ULONG i = UI2_MAX + 1; 1313 1314 VarUI4FromCy(cyIn, &i); 1315 return _VarUI2FromUI4(i, pusOut); 1316 } 1317 1318 /************************************************************************ 1319 * VarUI2FromStr (OLEAUT32.264) 1320 * 1321 * Convert a VT_BSTR to a VT_UI2. 1322 * 1323 * PARAMS 1324 * strIn [I] Source 1325 * lcid [I] LCID for the conversion 1326 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 1327 * pusOut [O] Destination 1328 * 1329 * RETURNS 1330 * Success: S_OK. 1331 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 1332 * DISP_E_TYPEMISMATCH, if the type cannot be converted 1333 */ 1334 HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* pusOut) 1335 { 1336 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pusOut, VT_UI2); 1337 } 1338 1339 /************************************************************************ 1340 * VarUI2FromDisp (OLEAUT32.265) 1341 * 1342 * Convert a VT_DISPATCH to a VT_UI2. 1343 * 1344 * PARAMS 1345 * pdispIn [I] Source 1346 * lcid [I] LCID for conversion 1347 * pusOut [O] Destination 1348 * 1349 * RETURNS 1350 * Success: S_OK. 1351 * Failure: E_INVALIDARG, if the source value is invalid 1352 * DISP_E_OVERFLOW, if the value will not fit in the destination 1353 * DISP_E_TYPEMISMATCH, if the type cannot be converted 1354 */ 1355 HRESULT WINAPI VarUI2FromDisp(IDispatch* pdispIn, LCID lcid, USHORT* pusOut) 1356 { 1357 return VARIANT_FromDisp(pdispIn, lcid, pusOut, VT_UI2, 0); 1358 } 1359 1360 /************************************************************************ 1361 * VarUI2FromBool (OLEAUT32.266) 1362 * 1363 * Convert a VT_BOOL to a VT_UI2. 1364 * 1365 * PARAMS 1366 * boolIn [I] Source 1367 * pusOut [O] Destination 1368 * 1369 * RETURNS 1370 * S_OK. 1371 */ 1372 HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* pusOut) 1373 { 1374 return _VarUI2FromBool(boolIn, pusOut); 1375 } 1376 1377 /************************************************************************ 1378 * VarUI2FromI1 (OLEAUT32.267) 1379 * 1380 * Convert a VT_I1 to a VT_UI2. 1381 * 1382 * PARAMS 1383 * cIn [I] Source 1384 * pusOut [O] Destination 1385 * 1386 * RETURNS 1387 * Success: S_OK. 1388 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 1389 */ 1390 HRESULT WINAPI VarUI2FromI1(signed char cIn, USHORT* pusOut) 1391 { 1392 return _VarUI2FromI1(cIn, pusOut); 1393 } 1394 1395 /************************************************************************ 1396 * VarUI2FromUI4 (OLEAUT32.268) 1397 * 1398 * Convert a VT_UI4 to a VT_UI2. 1399 * 1400 * PARAMS 1401 * ulIn [I] Source 1402 * pusOut [O] Destination 1403 * 1404 * RETURNS 1405 * Success: S_OK. 1406 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 1407 */ 1408 HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* pusOut) 1409 { 1410 return _VarUI2FromUI4(ulIn, pusOut); 1411 } 1412 1413 /************************************************************************ 1414 * VarUI2FromDec (OLEAUT32.269) 1415 * 1416 * Convert a VT_DECIMAL to a VT_UI2. 1417 * 1418 * PARAMS 1419 * pDecIn [I] Source 1420 * pusOut [O] Destination 1421 * 1422 * RETURNS 1423 * Success: S_OK. 1424 * Failure: E_INVALIDARG, if the source value is invalid 1425 * DISP_E_OVERFLOW, if the value will not fit in the destination 1426 */ 1427 HRESULT WINAPI VarUI2FromDec(DECIMAL *pdecIn, USHORT* pusOut) 1428 { 1429 LONG64 i64; 1430 HRESULT hRet; 1431 1432 hRet = VarI8FromDec(pdecIn, &i64); 1433 1434 if (SUCCEEDED(hRet)) 1435 hRet = _VarUI2FromI8(i64, pusOut); 1436 return hRet; 1437 } 1438 1439 /************************************************************************ 1440 * VarUI2FromI8 (OLEAUT32.378) 1441 * 1442 * Convert a VT_I8 to a VT_UI2. 1443 * 1444 * PARAMS 1445 * llIn [I] Source 1446 * pusOut [O] Destination 1447 * 1448 * RETURNS 1449 * Success: S_OK. 1450 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 1451 */ 1452 HRESULT WINAPI VarUI2FromI8(LONG64 llIn, USHORT* pusOut) 1453 { 1454 return _VarUI2FromI8(llIn, pusOut); 1455 } 1456 1457 /************************************************************************ 1458 * VarUI2FromUI8 (OLEAUT32.379) 1459 * 1460 * Convert a VT_UI8 to a VT_UI2. 1461 * 1462 * PARAMS 1463 * ullIn [I] Source 1464 * pusOut [O] Destination 1465 * 1466 * RETURNS 1467 * Success: S_OK. 1468 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 1469 */ 1470 HRESULT WINAPI VarUI2FromUI8(ULONG64 ullIn, USHORT* pusOut) 1471 { 1472 return _VarUI2FromUI8(ullIn, pusOut); 1473 } 1474 1475 /* I4 1476 */ 1477 1478 /************************************************************************ 1479 * VarI4FromUI1 (OLEAUT32.58) 1480 * 1481 * Convert a VT_UI1 to a VT_I4. 1482 * 1483 * PARAMS 1484 * bIn [I] Source 1485 * piOut [O] Destination 1486 * 1487 * RETURNS 1488 * S_OK. 1489 */ 1490 HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG *piOut) 1491 { 1492 return _VarI4FromUI1(bIn, piOut); 1493 } 1494 1495 /************************************************************************ 1496 * VarI4FromI2 (OLEAUT32.59) 1497 * 1498 * Convert a VT_I2 to a VT_I4. 1499 * 1500 * PARAMS 1501 * sIn [I] Source 1502 * piOut [O] Destination 1503 * 1504 * RETURNS 1505 * Success: S_OK. 1506 * Failure: E_INVALIDARG, if the source value is invalid 1507 * DISP_E_OVERFLOW, if the value will not fit in the destination 1508 */ 1509 HRESULT WINAPI VarI4FromI2(SHORT sIn, LONG *piOut) 1510 { 1511 return _VarI4FromI2(sIn, piOut); 1512 } 1513 1514 /************************************************************************ 1515 * VarI4FromR4 (OLEAUT32.60) 1516 * 1517 * Convert a VT_R4 to a VT_I4. 1518 * 1519 * PARAMS 1520 * fltIn [I] Source 1521 * piOut [O] Destination 1522 * 1523 * RETURNS 1524 * Success: S_OK. 1525 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 1526 */ 1527 HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG *piOut) 1528 { 1529 return VarI4FromR8(fltIn, piOut); 1530 } 1531 1532 /************************************************************************ 1533 * VarI4FromR8 (OLEAUT32.61) 1534 * 1535 * Convert a VT_R8 to a VT_I4. 1536 * 1537 * PARAMS 1538 * dblIn [I] Source 1539 * piOut [O] Destination 1540 * 1541 * RETURNS 1542 * Success: S_OK. 1543 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 1544 * 1545 * NOTES 1546 * See VarI8FromR8() for details concerning rounding. 1547 */ 1548 HRESULT WINAPI VarI4FromR8(double dblIn, LONG *piOut) 1549 { 1550 if (dblIn < I4_MIN - 0.5 || dblIn >= I4_MAX + 0.5) 1551 return DISP_E_OVERFLOW; 1552 VARIANT_DutchRound(LONG, dblIn, *piOut); 1553 return S_OK; 1554 } 1555 1556 /************************************************************************ 1557 * VarI4FromCy (OLEAUT32.62) 1558 * 1559 * Convert a VT_CY to a VT_I4. 1560 * 1561 * PARAMS 1562 * cyIn [I] Source 1563 * piOut [O] Destination 1564 * 1565 * RETURNS 1566 * Success: S_OK. 1567 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 1568 */ 1569 HRESULT WINAPI VarI4FromCy(CY cyIn, LONG *piOut) 1570 { 1571 double d = cyIn.int64 / CY_MULTIPLIER_F; 1572 return VarI4FromR8(d, piOut); 1573 } 1574 1575 /************************************************************************ 1576 * VarI4FromDate (OLEAUT32.63) 1577 * 1578 * Convert a VT_DATE to a VT_I4. 1579 * 1580 * PARAMS 1581 * dateIn [I] Source 1582 * piOut [O] Destination 1583 * 1584 * RETURNS 1585 * Success: S_OK. 1586 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 1587 */ 1588 HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG *piOut) 1589 { 1590 return VarI4FromR8(dateIn, piOut); 1591 } 1592 1593 /************************************************************************ 1594 * VarI4FromStr (OLEAUT32.64) 1595 * 1596 * Convert a VT_BSTR to a VT_I4. 1597 * 1598 * PARAMS 1599 * strIn [I] Source 1600 * lcid [I] LCID for the conversion 1601 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 1602 * piOut [O] Destination 1603 * 1604 * RETURNS 1605 * Success: S_OK. 1606 * Failure: E_INVALIDARG, if any parameter is invalid 1607 * DISP_E_OVERFLOW, if the value will not fit in the destination 1608 * DISP_E_TYPEMISMATCH, if strIn cannot be converted 1609 */ 1610 HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG *piOut) 1611 { 1612 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, piOut, VT_I4); 1613 } 1614 1615 /************************************************************************ 1616 * VarI4FromDisp (OLEAUT32.65) 1617 * 1618 * Convert a VT_DISPATCH to a VT_I4. 1619 * 1620 * PARAMS 1621 * pdispIn [I] Source 1622 * lcid [I] LCID for conversion 1623 * piOut [O] Destination 1624 * 1625 * RETURNS 1626 * Success: S_OK. 1627 * Failure: E_INVALIDARG, if the source value is invalid 1628 * DISP_E_OVERFLOW, if the value will not fit in the destination 1629 * DISP_E_TYPEMISMATCH, if the type cannot be converted 1630 */ 1631 HRESULT WINAPI VarI4FromDisp(IDispatch* pdispIn, LCID lcid, LONG *piOut) 1632 { 1633 return VARIANT_FromDisp(pdispIn, lcid, piOut, VT_I4, 0); 1634 } 1635 1636 /************************************************************************ 1637 * VarI4FromBool (OLEAUT32.66) 1638 * 1639 * Convert a VT_BOOL to a VT_I4. 1640 * 1641 * PARAMS 1642 * boolIn [I] Source 1643 * piOut [O] Destination 1644 * 1645 * RETURNS 1646 * S_OK. 1647 */ 1648 HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG *piOut) 1649 { 1650 return _VarI4FromBool(boolIn, piOut); 1651 } 1652 1653 /************************************************************************ 1654 * VarI4FromI1 (OLEAUT32.209) 1655 * 1656 * Convert a VT_I1 to a VT_I4. 1657 * 1658 * PARAMS 1659 * cIn [I] Source 1660 * piOut [O] Destination 1661 * 1662 * RETURNS 1663 * S_OK. 1664 */ 1665 HRESULT WINAPI VarI4FromI1(signed char cIn, LONG *piOut) 1666 { 1667 return _VarI4FromI1(cIn, piOut); 1668 } 1669 1670 /************************************************************************ 1671 * VarI4FromUI2 (OLEAUT32.210) 1672 * 1673 * Convert a VT_UI2 to a VT_I4. 1674 * 1675 * PARAMS 1676 * usIn [I] Source 1677 * piOut [O] Destination 1678 * 1679 * RETURNS 1680 * S_OK. 1681 */ 1682 HRESULT WINAPI VarI4FromUI2(USHORT usIn, LONG *piOut) 1683 { 1684 return _VarI4FromUI2(usIn, piOut); 1685 } 1686 1687 /************************************************************************ 1688 * VarI4FromUI4 (OLEAUT32.211) 1689 * 1690 * Convert a VT_UI4 to a VT_I4. 1691 * 1692 * PARAMS 1693 * ulIn [I] Source 1694 * piOut [O] Destination 1695 * 1696 * RETURNS 1697 * Success: S_OK. 1698 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 1699 */ 1700 HRESULT WINAPI VarI4FromUI4(ULONG ulIn, LONG *piOut) 1701 { 1702 return _VarI4FromUI4(ulIn, piOut); 1703 } 1704 1705 /************************************************************************ 1706 * VarI4FromDec (OLEAUT32.212) 1707 * 1708 * Convert a VT_DECIMAL to a VT_I4. 1709 * 1710 * PARAMS 1711 * pDecIn [I] Source 1712 * piOut [O] Destination 1713 * 1714 * RETURNS 1715 * Success: S_OK. 1716 * Failure: E_INVALIDARG, if pdecIn is invalid 1717 * DISP_E_OVERFLOW, if the value will not fit in the destination 1718 */ 1719 HRESULT WINAPI VarI4FromDec(DECIMAL *pdecIn, LONG *piOut) 1720 { 1721 LONG64 i64; 1722 HRESULT hRet; 1723 1724 hRet = VarI8FromDec(pdecIn, &i64); 1725 1726 if (SUCCEEDED(hRet)) 1727 hRet = _VarI4FromI8(i64, piOut); 1728 return hRet; 1729 } 1730 1731 /************************************************************************ 1732 * VarI4FromI8 (OLEAUT32.348) 1733 * 1734 * Convert a VT_I8 to a VT_I4. 1735 * 1736 * PARAMS 1737 * llIn [I] Source 1738 * piOut [O] Destination 1739 * 1740 * RETURNS 1741 * Success: S_OK. 1742 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 1743 */ 1744 HRESULT WINAPI VarI4FromI8(LONG64 llIn, LONG *piOut) 1745 { 1746 return _VarI4FromI8(llIn, piOut); 1747 } 1748 1749 /************************************************************************ 1750 * VarI4FromUI8 (OLEAUT32.349) 1751 * 1752 * Convert a VT_UI8 to a VT_I4. 1753 * 1754 * PARAMS 1755 * ullIn [I] Source 1756 * piOut [O] Destination 1757 * 1758 * RETURNS 1759 * Success: S_OK. 1760 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 1761 */ 1762 HRESULT WINAPI VarI4FromUI8(ULONG64 ullIn, LONG *piOut) 1763 { 1764 return _VarI4FromUI8(ullIn, piOut); 1765 } 1766 1767 /* UI4 1768 */ 1769 1770 /************************************************************************ 1771 * VarUI4FromUI1 (OLEAUT32.270) 1772 * 1773 * Convert a VT_UI1 to a VT_UI4. 1774 * 1775 * PARAMS 1776 * bIn [I] Source 1777 * pulOut [O] Destination 1778 * 1779 * RETURNS 1780 * S_OK. 1781 */ 1782 HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG *pulOut) 1783 { 1784 return _VarUI4FromUI1(bIn, pulOut); 1785 } 1786 1787 /************************************************************************ 1788 * VarUI4FromI2 (OLEAUT32.271) 1789 * 1790 * Convert a VT_I2 to a VT_UI4. 1791 * 1792 * PARAMS 1793 * sIn [I] Source 1794 * pulOut [O] Destination 1795 * 1796 * RETURNS 1797 * Success: S_OK. 1798 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 1799 */ 1800 HRESULT WINAPI VarUI4FromI2(SHORT sIn, ULONG *pulOut) 1801 { 1802 return _VarUI4FromI2(sIn, pulOut); 1803 } 1804 1805 /************************************************************************ 1806 * VarUI4FromI4 (OLEAUT32.272) 1807 * 1808 * Convert a VT_I4 to a VT_UI4. 1809 * 1810 * PARAMS 1811 * iIn [I] Source 1812 * pulOut [O] Destination 1813 * 1814 * RETURNS 1815 * Success: S_OK. 1816 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 1817 */ 1818 HRESULT WINAPI VarUI4FromI4(LONG iIn, ULONG *pulOut) 1819 { 1820 return _VarUI4FromI4(iIn, pulOut); 1821 } 1822 1823 /************************************************************************ 1824 * VarUI4FromR4 (OLEAUT32.273) 1825 * 1826 * Convert a VT_R4 to a VT_UI4. 1827 * 1828 * PARAMS 1829 * fltIn [I] Source 1830 * pulOut [O] Destination 1831 * 1832 * RETURNS 1833 * Success: S_OK. 1834 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 1835 */ 1836 HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG *pulOut) 1837 { 1838 return VarUI4FromR8(fltIn, pulOut); 1839 } 1840 1841 /************************************************************************ 1842 * VarUI4FromR8 (OLEAUT32.274) 1843 * 1844 * Convert a VT_R8 to a VT_UI4. 1845 * 1846 * PARAMS 1847 * dblIn [I] Source 1848 * pulOut [O] Destination 1849 * 1850 * RETURNS 1851 * Success: S_OK. 1852 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 1853 * 1854 * NOTES 1855 * See VarI8FromR8() for details concerning rounding. 1856 */ 1857 HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG *pulOut) 1858 { 1859 if (dblIn < -0.5 || dblIn >= UI4_MAX + 0.5) 1860 return DISP_E_OVERFLOW; 1861 VARIANT_DutchRound(ULONG, dblIn, *pulOut); 1862 return S_OK; 1863 } 1864 1865 /************************************************************************ 1866 * VarUI4FromDate (OLEAUT32.275) 1867 * 1868 * Convert a VT_DATE to a VT_UI4. 1869 * 1870 * PARAMS 1871 * dateIn [I] Source 1872 * pulOut [O] Destination 1873 * 1874 * RETURNS 1875 * Success: S_OK. 1876 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 1877 */ 1878 HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG *pulOut) 1879 { 1880 return VarUI4FromR8(dateIn, pulOut); 1881 } 1882 1883 /************************************************************************ 1884 * VarUI4FromCy (OLEAUT32.276) 1885 * 1886 * Convert a VT_CY to a VT_UI4. 1887 * 1888 * PARAMS 1889 * cyIn [I] Source 1890 * pulOut [O] Destination 1891 * 1892 * RETURNS 1893 * Success: S_OK. 1894 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 1895 */ 1896 HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG *pulOut) 1897 { 1898 double d = cyIn.int64 / CY_MULTIPLIER_F; 1899 return VarUI4FromR8(d, pulOut); 1900 } 1901 1902 /************************************************************************ 1903 * VarUI4FromStr (OLEAUT32.277) 1904 * 1905 * Convert a VT_BSTR to a VT_UI4. 1906 * 1907 * PARAMS 1908 * strIn [I] Source 1909 * lcid [I] LCID for the conversion 1910 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 1911 * pulOut [O] Destination 1912 * 1913 * RETURNS 1914 * Success: S_OK. 1915 * Failure: E_INVALIDARG, if any parameter is invalid 1916 * DISP_E_OVERFLOW, if the value will not fit in the destination 1917 * DISP_E_TYPEMISMATCH, if strIn cannot be converted 1918 */ 1919 HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG *pulOut) 1920 { 1921 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pulOut, VT_UI4); 1922 } 1923 1924 /************************************************************************ 1925 * VarUI4FromDisp (OLEAUT32.278) 1926 * 1927 * Convert a VT_DISPATCH to a VT_UI4. 1928 * 1929 * PARAMS 1930 * pdispIn [I] Source 1931 * lcid [I] LCID for conversion 1932 * pulOut [O] Destination 1933 * 1934 * RETURNS 1935 * Success: S_OK. 1936 * Failure: E_INVALIDARG, if the source value is invalid 1937 * DISP_E_OVERFLOW, if the value will not fit in the destination 1938 * DISP_E_TYPEMISMATCH, if the type cannot be converted 1939 */ 1940 HRESULT WINAPI VarUI4FromDisp(IDispatch* pdispIn, LCID lcid, ULONG *pulOut) 1941 { 1942 return VARIANT_FromDisp(pdispIn, lcid, pulOut, VT_UI4, 0); 1943 } 1944 1945 /************************************************************************ 1946 * VarUI4FromBool (OLEAUT32.279) 1947 * 1948 * Convert a VT_BOOL to a VT_UI4. 1949 * 1950 * PARAMS 1951 * boolIn [I] Source 1952 * pulOut [O] Destination 1953 * 1954 * RETURNS 1955 * S_OK. 1956 */ 1957 HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG *pulOut) 1958 { 1959 return _VarUI4FromBool(boolIn, pulOut); 1960 } 1961 1962 /************************************************************************ 1963 * VarUI4FromI1 (OLEAUT32.280) 1964 * 1965 * Convert a VT_I1 to a VT_UI4. 1966 * 1967 * PARAMS 1968 * cIn [I] Source 1969 * pulOut [O] Destination 1970 * 1971 * RETURNS 1972 * Success: S_OK. 1973 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 1974 */ 1975 HRESULT WINAPI VarUI4FromI1(signed char cIn, ULONG *pulOut) 1976 { 1977 return _VarUI4FromI1(cIn, pulOut); 1978 } 1979 1980 /************************************************************************ 1981 * VarUI4FromUI2 (OLEAUT32.281) 1982 * 1983 * Convert a VT_UI2 to a VT_UI4. 1984 * 1985 * PARAMS 1986 * usIn [I] Source 1987 * pulOut [O] Destination 1988 * 1989 * RETURNS 1990 * S_OK. 1991 */ 1992 HRESULT WINAPI VarUI4FromUI2(USHORT usIn, ULONG *pulOut) 1993 { 1994 return _VarUI4FromUI2(usIn, pulOut); 1995 } 1996 1997 /************************************************************************ 1998 * VarUI4FromDec (OLEAUT32.282) 1999 * 2000 * Convert a VT_DECIMAL to a VT_UI4. 2001 * 2002 * PARAMS 2003 * pDecIn [I] Source 2004 * pulOut [O] Destination 2005 * 2006 * RETURNS 2007 * Success: S_OK. 2008 * Failure: E_INVALIDARG, if pdecIn is invalid 2009 * DISP_E_OVERFLOW, if the value will not fit in the destination 2010 */ 2011 HRESULT WINAPI VarUI4FromDec(DECIMAL *pdecIn, ULONG *pulOut) 2012 { 2013 LONG64 i64; 2014 HRESULT hRet; 2015 2016 hRet = VarI8FromDec(pdecIn, &i64); 2017 2018 if (SUCCEEDED(hRet)) 2019 hRet = _VarUI4FromI8(i64, pulOut); 2020 return hRet; 2021 } 2022 2023 /************************************************************************ 2024 * VarUI4FromI8 (OLEAUT32.425) 2025 * 2026 * Convert a VT_I8 to a VT_UI4. 2027 * 2028 * PARAMS 2029 * llIn [I] Source 2030 * pulOut [O] Destination 2031 * 2032 * RETURNS 2033 * Success: S_OK. 2034 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 2035 */ 2036 HRESULT WINAPI VarUI4FromI8(LONG64 llIn, ULONG *pulOut) 2037 { 2038 return _VarUI4FromI8(llIn, pulOut); 2039 } 2040 2041 /************************************************************************ 2042 * VarUI4FromUI8 (OLEAUT32.426) 2043 * 2044 * Convert a VT_UI8 to a VT_UI4. 2045 * 2046 * PARAMS 2047 * ullIn [I] Source 2048 * pulOut [O] Destination 2049 * 2050 * RETURNS 2051 * Success: S_OK. 2052 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 2053 */ 2054 HRESULT WINAPI VarUI4FromUI8(ULONG64 ullIn, ULONG *pulOut) 2055 { 2056 return _VarUI4FromUI8(ullIn, pulOut); 2057 } 2058 2059 /* I8 2060 */ 2061 2062 /************************************************************************ 2063 * VarI8FromUI1 (OLEAUT32.333) 2064 * 2065 * Convert a VT_UI1 to a VT_I8. 2066 * 2067 * PARAMS 2068 * bIn [I] Source 2069 * pi64Out [O] Destination 2070 * 2071 * RETURNS 2072 * S_OK. 2073 */ 2074 HRESULT WINAPI VarI8FromUI1(BYTE bIn, LONG64* pi64Out) 2075 { 2076 return _VarI8FromUI1(bIn, pi64Out); 2077 } 2078 2079 2080 /************************************************************************ 2081 * VarI8FromI2 (OLEAUT32.334) 2082 * 2083 * Convert a VT_I2 to a VT_I8. 2084 * 2085 * PARAMS 2086 * sIn [I] Source 2087 * pi64Out [O] Destination 2088 * 2089 * RETURNS 2090 * S_OK. 2091 */ 2092 HRESULT WINAPI VarI8FromI2(SHORT sIn, LONG64* pi64Out) 2093 { 2094 return _VarI8FromI2(sIn, pi64Out); 2095 } 2096 2097 /************************************************************************ 2098 * VarI8FromR4 (OLEAUT32.335) 2099 * 2100 * Convert a VT_R4 to a VT_I8. 2101 * 2102 * PARAMS 2103 * fltIn [I] Source 2104 * pi64Out [O] Destination 2105 * 2106 * RETURNS 2107 * Success: S_OK. 2108 * Failure: E_INVALIDARG, if the source value is invalid 2109 * DISP_E_OVERFLOW, if the value will not fit in the destination 2110 */ 2111 HRESULT WINAPI VarI8FromR4(FLOAT fltIn, LONG64* pi64Out) 2112 { 2113 return VarI8FromR8(fltIn, pi64Out); 2114 } 2115 2116 /************************************************************************ 2117 * VarI8FromR8 (OLEAUT32.336) 2118 * 2119 * Convert a VT_R8 to a VT_I8. 2120 * 2121 * PARAMS 2122 * dblIn [I] Source 2123 * pi64Out [O] Destination 2124 * 2125 * RETURNS 2126 * Success: S_OK. 2127 * Failure: E_INVALIDARG, if the source value is invalid 2128 * DISP_E_OVERFLOW, if the value will not fit in the destination 2129 * 2130 * NOTES 2131 * Only values that fit into 63 bits are accepted. Due to rounding issues, 2132 * very high or low values will not be accurately converted. 2133 * 2134 * Numbers are rounded using Dutch rounding, as follows: 2135 * 2136 *| Fractional Part Sign Direction Example 2137 *| --------------- ---- --------- ------- 2138 *| < 0.5 + Down 0.4 -> 0.0 2139 *| < 0.5 - Up -0.4 -> 0.0 2140 *| > 0.5 + Up 0.6 -> 1.0 2141 *| < 0.5 - Up -0.6 -> -1.0 2142 *| = 0.5 + Up/Down Down if even, Up if odd 2143 *| = 0.5 - Up/Down Up if even, Down if odd 2144 * 2145 * This system is often used in supermarkets. 2146 */ 2147 HRESULT WINAPI VarI8FromR8(double dblIn, LONG64* pi64Out) 2148 { 2149 if ( dblIn < -4611686018427387904.0 || dblIn >= 4611686018427387904.0) 2150 return DISP_E_OVERFLOW; 2151 VARIANT_DutchRound(LONG64, dblIn, *pi64Out); 2152 return S_OK; 2153 } 2154 2155 /************************************************************************ 2156 * VarI8FromCy (OLEAUT32.337) 2157 * 2158 * Convert a VT_CY to a VT_I8. 2159 * 2160 * PARAMS 2161 * cyIn [I] Source 2162 * pi64Out [O] Destination 2163 * 2164 * RETURNS 2165 * S_OK. 2166 * 2167 * NOTES 2168 * All negative numbers are rounded down by 1, including those that are 2169 * evenly divisible by 10000 (this is a Win32 bug that Wine mimics). 2170 * Positive numbers are rounded using Dutch rounding: See VarI8FromR8() 2171 * for details. 2172 */ 2173 HRESULT WINAPI VarI8FromCy(CY cyIn, LONG64* pi64Out) 2174 { 2175 *pi64Out = cyIn.int64 / CY_MULTIPLIER; 2176 2177 if (cyIn.int64 < 0) 2178 (*pi64Out)--; /* Mimic Win32 bug */ 2179 else 2180 { 2181 cyIn.int64 -= *pi64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */ 2182 2183 if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pi64Out & 0x1))) 2184 (*pi64Out)++; 2185 } 2186 return S_OK; 2187 } 2188 2189 /************************************************************************ 2190 * VarI8FromDate (OLEAUT32.338) 2191 * 2192 * Convert a VT_DATE to a VT_I8. 2193 * 2194 * PARAMS 2195 * dateIn [I] Source 2196 * pi64Out [O] Destination 2197 * 2198 * RETURNS 2199 * Success: S_OK. 2200 * Failure: E_INVALIDARG, if the source value is invalid 2201 * DISP_E_OVERFLOW, if the value will not fit in the destination 2202 * DISP_E_TYPEMISMATCH, if the type cannot be converted 2203 */ 2204 HRESULT WINAPI VarI8FromDate(DATE dateIn, LONG64* pi64Out) 2205 { 2206 return VarI8FromR8(dateIn, pi64Out); 2207 } 2208 2209 /************************************************************************ 2210 * VarI8FromStr (OLEAUT32.339) 2211 * 2212 * Convert a VT_BSTR to a VT_I8. 2213 * 2214 * PARAMS 2215 * strIn [I] Source 2216 * lcid [I] LCID for the conversion 2217 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 2218 * pi64Out [O] Destination 2219 * 2220 * RETURNS 2221 * Success: S_OK. 2222 * Failure: E_INVALIDARG, if the source value is invalid 2223 * DISP_E_OVERFLOW, if the value will not fit in the destination 2224 * DISP_E_TYPEMISMATCH, if the type cannot be converted 2225 */ 2226 HRESULT WINAPI VarI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG64* pi64Out) 2227 { 2228 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pi64Out, VT_I8); 2229 } 2230 2231 /************************************************************************ 2232 * VarI8FromDisp (OLEAUT32.340) 2233 * 2234 * Convert a VT_DISPATCH to a VT_I8. 2235 * 2236 * PARAMS 2237 * pdispIn [I] Source 2238 * lcid [I] LCID for conversion 2239 * pi64Out [O] Destination 2240 * 2241 * RETURNS 2242 * Success: S_OK. 2243 * Failure: E_INVALIDARG, if the source value is invalid 2244 * DISP_E_OVERFLOW, if the value will not fit in the destination 2245 * DISP_E_TYPEMISMATCH, if the type cannot be converted 2246 */ 2247 HRESULT WINAPI VarI8FromDisp(IDispatch* pdispIn, LCID lcid, LONG64* pi64Out) 2248 { 2249 return VARIANT_FromDisp(pdispIn, lcid, pi64Out, VT_I8, 0); 2250 } 2251 2252 /************************************************************************ 2253 * VarI8FromBool (OLEAUT32.341) 2254 * 2255 * Convert a VT_BOOL to a VT_I8. 2256 * 2257 * PARAMS 2258 * boolIn [I] Source 2259 * pi64Out [O] Destination 2260 * 2261 * RETURNS 2262 * S_OK. 2263 */ 2264 HRESULT WINAPI VarI8FromBool(VARIANT_BOOL boolIn, LONG64* pi64Out) 2265 { 2266 return VarI8FromI2(boolIn, pi64Out); 2267 } 2268 2269 /************************************************************************ 2270 * VarI8FromI1 (OLEAUT32.342) 2271 * 2272 * Convert a VT_I1 to a VT_I8. 2273 * 2274 * PARAMS 2275 * cIn [I] Source 2276 * pi64Out [O] Destination 2277 * 2278 * RETURNS 2279 * S_OK. 2280 */ 2281 HRESULT WINAPI VarI8FromI1(signed char cIn, LONG64* pi64Out) 2282 { 2283 return _VarI8FromI1(cIn, pi64Out); 2284 } 2285 2286 /************************************************************************ 2287 * VarI8FromUI2 (OLEAUT32.343) 2288 * 2289 * Convert a VT_UI2 to a VT_I8. 2290 * 2291 * PARAMS 2292 * usIn [I] Source 2293 * pi64Out [O] Destination 2294 * 2295 * RETURNS 2296 * S_OK. 2297 */ 2298 HRESULT WINAPI VarI8FromUI2(USHORT usIn, LONG64* pi64Out) 2299 { 2300 return _VarI8FromUI2(usIn, pi64Out); 2301 } 2302 2303 /************************************************************************ 2304 * VarI8FromUI4 (OLEAUT32.344) 2305 * 2306 * Convert a VT_UI4 to a VT_I8. 2307 * 2308 * PARAMS 2309 * ulIn [I] Source 2310 * pi64Out [O] Destination 2311 * 2312 * RETURNS 2313 * S_OK. 2314 */ 2315 HRESULT WINAPI VarI8FromUI4(ULONG ulIn, LONG64* pi64Out) 2316 { 2317 return _VarI8FromUI4(ulIn, pi64Out); 2318 } 2319 2320 /************************************************************************ 2321 * VarI8FromDec (OLEAUT32.345) 2322 * 2323 * Convert a VT_DECIMAL to a VT_I8. 2324 * 2325 * PARAMS 2326 * pDecIn [I] Source 2327 * pi64Out [O] Destination 2328 * 2329 * RETURNS 2330 * Success: S_OK. 2331 * Failure: E_INVALIDARG, if the source value is invalid 2332 * DISP_E_OVERFLOW, if the value will not fit in the destination 2333 */ 2334 HRESULT WINAPI VarI8FromDec(DECIMAL *pdecIn, LONG64* pi64Out) 2335 { 2336 if (!DEC_SCALE(pdecIn)) 2337 { 2338 /* This decimal is just a 96 bit integer */ 2339 if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG) 2340 return E_INVALIDARG; 2341 2342 if (DEC_HI32(pdecIn) || DEC_MID32(pdecIn) & 0x80000000) 2343 return DISP_E_OVERFLOW; 2344 2345 if (DEC_SIGN(pdecIn)) 2346 *pi64Out = -DEC_LO64(pdecIn); 2347 else 2348 *pi64Out = DEC_LO64(pdecIn); 2349 return S_OK; 2350 } 2351 else 2352 { 2353 /* Decimal contains a floating point number */ 2354 HRESULT hRet; 2355 double dbl; 2356 2357 hRet = VarR8FromDec(pdecIn, &dbl); 2358 if (SUCCEEDED(hRet)) 2359 hRet = VarI8FromR8(dbl, pi64Out); 2360 return hRet; 2361 } 2362 } 2363 2364 /************************************************************************ 2365 * VarI8FromUI8 (OLEAUT32.427) 2366 * 2367 * Convert a VT_UI8 to a VT_I8. 2368 * 2369 * PARAMS 2370 * ullIn [I] Source 2371 * pi64Out [O] Destination 2372 * 2373 * RETURNS 2374 * Success: S_OK. 2375 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 2376 */ 2377 HRESULT WINAPI VarI8FromUI8(ULONG64 ullIn, LONG64* pi64Out) 2378 { 2379 return _VarI8FromUI8(ullIn, pi64Out); 2380 } 2381 2382 /* UI8 2383 */ 2384 2385 /************************************************************************ 2386 * VarUI8FromI8 (OLEAUT32.428) 2387 * 2388 * Convert a VT_I8 to a VT_UI8. 2389 * 2390 * PARAMS 2391 * ulIn [I] Source 2392 * pui64Out [O] Destination 2393 * 2394 * RETURNS 2395 * Success: S_OK. 2396 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 2397 */ 2398 HRESULT WINAPI VarUI8FromI8(LONG64 llIn, ULONG64* pui64Out) 2399 { 2400 return _VarUI8FromI8(llIn, pui64Out); 2401 } 2402 2403 /************************************************************************ 2404 * VarUI8FromUI1 (OLEAUT32.429) 2405 * 2406 * Convert a VT_UI1 to a VT_UI8. 2407 * 2408 * PARAMS 2409 * bIn [I] Source 2410 * pui64Out [O] Destination 2411 * 2412 * RETURNS 2413 * S_OK. 2414 */ 2415 HRESULT WINAPI VarUI8FromUI1(BYTE bIn, ULONG64* pui64Out) 2416 { 2417 return _VarUI8FromUI1(bIn, pui64Out); 2418 } 2419 2420 /************************************************************************ 2421 * VarUI8FromI2 (OLEAUT32.430) 2422 * 2423 * Convert a VT_I2 to a VT_UI8. 2424 * 2425 * PARAMS 2426 * sIn [I] Source 2427 * pui64Out [O] Destination 2428 * 2429 * RETURNS 2430 * S_OK. 2431 */ 2432 HRESULT WINAPI VarUI8FromI2(SHORT sIn, ULONG64* pui64Out) 2433 { 2434 return _VarUI8FromI2(sIn, pui64Out); 2435 } 2436 2437 /************************************************************************ 2438 * VarUI8FromR4 (OLEAUT32.431) 2439 * 2440 * Convert a VT_R4 to a VT_UI8. 2441 * 2442 * PARAMS 2443 * fltIn [I] Source 2444 * pui64Out [O] Destination 2445 * 2446 * RETURNS 2447 * Success: S_OK. 2448 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 2449 */ 2450 HRESULT WINAPI VarUI8FromR4(FLOAT fltIn, ULONG64* pui64Out) 2451 { 2452 return VarUI8FromR8(fltIn, pui64Out); 2453 } 2454 2455 /************************************************************************ 2456 * VarUI8FromR8 (OLEAUT32.432) 2457 * 2458 * Convert a VT_R8 to a VT_UI8. 2459 * 2460 * PARAMS 2461 * dblIn [I] Source 2462 * pui64Out [O] Destination 2463 * 2464 * RETURNS 2465 * Success: S_OK. 2466 * Failure: E_INVALIDARG, if the source value is invalid 2467 * DISP_E_OVERFLOW, if the value will not fit in the destination 2468 * 2469 * NOTES 2470 * See VarI8FromR8() for details concerning rounding. 2471 */ 2472 HRESULT WINAPI VarUI8FromR8(double dblIn, ULONG64* pui64Out) 2473 { 2474 if (dblIn < -0.5 || dblIn > 1.844674407370955e19) 2475 return DISP_E_OVERFLOW; 2476 VARIANT_DutchRound(ULONG64, dblIn, *pui64Out); 2477 return S_OK; 2478 } 2479 2480 /************************************************************************ 2481 * VarUI8FromCy (OLEAUT32.433) 2482 * 2483 * Convert a VT_CY to a VT_UI8. 2484 * 2485 * PARAMS 2486 * cyIn [I] Source 2487 * pui64Out [O] Destination 2488 * 2489 * RETURNS 2490 * Success: S_OK. 2491 * Failure: E_INVALIDARG, if the source value is invalid 2492 * DISP_E_OVERFLOW, if the value will not fit in the destination 2493 * 2494 * NOTES 2495 * Negative values >= -5000 will be converted to 0. 2496 */ 2497 HRESULT WINAPI VarUI8FromCy(CY cyIn, ULONG64* pui64Out) 2498 { 2499 if (cyIn.int64 < 0) 2500 { 2501 if (cyIn.int64 < -CY_HALF) 2502 return DISP_E_OVERFLOW; 2503 *pui64Out = 0; 2504 } 2505 else 2506 { 2507 *pui64Out = cyIn.int64 / CY_MULTIPLIER; 2508 2509 cyIn.int64 -= *pui64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */ 2510 2511 if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pui64Out & 0x1))) 2512 (*pui64Out)++; 2513 } 2514 return S_OK; 2515 } 2516 2517 /************************************************************************ 2518 * VarUI8FromDate (OLEAUT32.434) 2519 * 2520 * Convert a VT_DATE to a VT_UI8. 2521 * 2522 * PARAMS 2523 * dateIn [I] Source 2524 * pui64Out [O] Destination 2525 * 2526 * RETURNS 2527 * Success: S_OK. 2528 * Failure: E_INVALIDARG, if the source value is invalid 2529 * DISP_E_OVERFLOW, if the value will not fit in the destination 2530 * DISP_E_TYPEMISMATCH, if the type cannot be converted 2531 */ 2532 HRESULT WINAPI VarUI8FromDate(DATE dateIn, ULONG64* pui64Out) 2533 { 2534 return VarUI8FromR8(dateIn, pui64Out); 2535 } 2536 2537 /************************************************************************ 2538 * VarUI8FromStr (OLEAUT32.435) 2539 * 2540 * Convert a VT_BSTR to a VT_UI8. 2541 * 2542 * PARAMS 2543 * strIn [I] Source 2544 * lcid [I] LCID for the conversion 2545 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 2546 * pui64Out [O] Destination 2547 * 2548 * RETURNS 2549 * Success: S_OK. 2550 * Failure: E_INVALIDARG, if the source value is invalid 2551 * DISP_E_OVERFLOW, if the value will not fit in the destination 2552 * DISP_E_TYPEMISMATCH, if the type cannot be converted 2553 */ 2554 HRESULT WINAPI VarUI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG64* pui64Out) 2555 { 2556 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pui64Out, VT_UI8); 2557 } 2558 2559 /************************************************************************ 2560 * VarUI8FromDisp (OLEAUT32.436) 2561 * 2562 * Convert a VT_DISPATCH to a VT_UI8. 2563 * 2564 * PARAMS 2565 * pdispIn [I] Source 2566 * lcid [I] LCID for conversion 2567 * pui64Out [O] Destination 2568 * 2569 * RETURNS 2570 * Success: S_OK. 2571 * Failure: E_INVALIDARG, if the source value is invalid 2572 * DISP_E_OVERFLOW, if the value will not fit in the destination 2573 * DISP_E_TYPEMISMATCH, if the type cannot be converted 2574 */ 2575 HRESULT WINAPI VarUI8FromDisp(IDispatch* pdispIn, LCID lcid, ULONG64* pui64Out) 2576 { 2577 return VARIANT_FromDisp(pdispIn, lcid, pui64Out, VT_UI8, 0); 2578 } 2579 2580 /************************************************************************ 2581 * VarUI8FromBool (OLEAUT32.437) 2582 * 2583 * Convert a VT_BOOL to a VT_UI8. 2584 * 2585 * PARAMS 2586 * boolIn [I] Source 2587 * pui64Out [O] Destination 2588 * 2589 * RETURNS 2590 * Success: S_OK. 2591 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 2592 */ 2593 HRESULT WINAPI VarUI8FromBool(VARIANT_BOOL boolIn, ULONG64* pui64Out) 2594 { 2595 return VarI8FromI2(boolIn, (LONG64 *)pui64Out); 2596 } 2597 /************************************************************************ 2598 * VarUI8FromI1 (OLEAUT32.438) 2599 * 2600 * Convert a VT_I1 to a VT_UI8. 2601 * 2602 * PARAMS 2603 * cIn [I] Source 2604 * pui64Out [O] Destination 2605 * 2606 * RETURNS 2607 * Success: S_OK. 2608 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 2609 */ 2610 HRESULT WINAPI VarUI8FromI1(signed char cIn, ULONG64* pui64Out) 2611 { 2612 return _VarUI8FromI1(cIn, pui64Out); 2613 } 2614 2615 /************************************************************************ 2616 * VarUI8FromUI2 (OLEAUT32.439) 2617 * 2618 * Convert a VT_UI2 to a VT_UI8. 2619 * 2620 * PARAMS 2621 * usIn [I] Source 2622 * pui64Out [O] Destination 2623 * 2624 * RETURNS 2625 * S_OK. 2626 */ 2627 HRESULT WINAPI VarUI8FromUI2(USHORT usIn, ULONG64* pui64Out) 2628 { 2629 return _VarUI8FromUI2(usIn, pui64Out); 2630 } 2631 2632 /************************************************************************ 2633 * VarUI8FromUI4 (OLEAUT32.440) 2634 * 2635 * Convert a VT_UI4 to a VT_UI8. 2636 * 2637 * PARAMS 2638 * ulIn [I] Source 2639 * pui64Out [O] Destination 2640 * 2641 * RETURNS 2642 * S_OK. 2643 */ 2644 HRESULT WINAPI VarUI8FromUI4(ULONG ulIn, ULONG64* pui64Out) 2645 { 2646 return _VarUI8FromUI4(ulIn, pui64Out); 2647 } 2648 2649 /************************************************************************ 2650 * VarUI8FromDec (OLEAUT32.441) 2651 * 2652 * Convert a VT_DECIMAL to a VT_UI8. 2653 * 2654 * PARAMS 2655 * pDecIn [I] Source 2656 * pui64Out [O] Destination 2657 * 2658 * RETURNS 2659 * Success: S_OK. 2660 * Failure: E_INVALIDARG, if the source value is invalid 2661 * DISP_E_OVERFLOW, if the value will not fit in the destination 2662 * 2663 * NOTES 2664 * Under native Win32, if the source value has a scale of 0, its sign is 2665 * ignored, i.e. this function takes the absolute value rather than fail 2666 * with DISP_E_OVERFLOW. This bug has been fixed in Wine's implementation 2667 * (use VarAbs() on pDecIn first if you really want this behaviour). 2668 */ 2669 HRESULT WINAPI VarUI8FromDec(DECIMAL *pdecIn, ULONG64* pui64Out) 2670 { 2671 if (!DEC_SCALE(pdecIn)) 2672 { 2673 /* This decimal is just a 96 bit integer */ 2674 if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG) 2675 return E_INVALIDARG; 2676 2677 if (DEC_HI32(pdecIn)) 2678 return DISP_E_OVERFLOW; 2679 2680 if (DEC_SIGN(pdecIn)) 2681 { 2682 WARN("Sign would be ignored under Win32!\n"); 2683 return DISP_E_OVERFLOW; 2684 } 2685 2686 *pui64Out = DEC_LO64(pdecIn); 2687 return S_OK; 2688 } 2689 else 2690 { 2691 /* Decimal contains a floating point number */ 2692 HRESULT hRet; 2693 double dbl; 2694 2695 hRet = VarR8FromDec(pdecIn, &dbl); 2696 if (SUCCEEDED(hRet)) 2697 hRet = VarUI8FromR8(dbl, pui64Out); 2698 return hRet; 2699 } 2700 } 2701 2702 /* R4 2703 */ 2704 2705 /************************************************************************ 2706 * VarR4FromUI1 (OLEAUT32.68) 2707 * 2708 * Convert a VT_UI1 to a VT_R4. 2709 * 2710 * PARAMS 2711 * bIn [I] Source 2712 * pFltOut [O] Destination 2713 * 2714 * RETURNS 2715 * S_OK. 2716 */ 2717 HRESULT WINAPI VarR4FromUI1(BYTE bIn, float *pFltOut) 2718 { 2719 return _VarR4FromUI1(bIn, pFltOut); 2720 } 2721 2722 /************************************************************************ 2723 * VarR4FromI2 (OLEAUT32.69) 2724 * 2725 * Convert a VT_I2 to a VT_R4. 2726 * 2727 * PARAMS 2728 * sIn [I] Source 2729 * pFltOut [O] Destination 2730 * 2731 * RETURNS 2732 * S_OK. 2733 */ 2734 HRESULT WINAPI VarR4FromI2(SHORT sIn, float *pFltOut) 2735 { 2736 return _VarR4FromI2(sIn, pFltOut); 2737 } 2738 2739 /************************************************************************ 2740 * VarR4FromI4 (OLEAUT32.70) 2741 * 2742 * Convert a VT_I4 to a VT_R4. 2743 * 2744 * PARAMS 2745 * sIn [I] Source 2746 * pFltOut [O] Destination 2747 * 2748 * RETURNS 2749 * S_OK. 2750 */ 2751 HRESULT WINAPI VarR4FromI4(LONG lIn, float *pFltOut) 2752 { 2753 return _VarR4FromI4(lIn, pFltOut); 2754 } 2755 2756 /************************************************************************ 2757 * VarR4FromR8 (OLEAUT32.71) 2758 * 2759 * Convert a VT_R8 to a VT_R4. 2760 * 2761 * PARAMS 2762 * dblIn [I] Source 2763 * pFltOut [O] Destination 2764 * 2765 * RETURNS 2766 * Success: S_OK. 2767 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination. 2768 */ 2769 HRESULT WINAPI VarR4FromR8(double dblIn, float *pFltOut) 2770 { 2771 double d = dblIn < 0.0 ? -dblIn : dblIn; 2772 if (d > R4_MAX) return DISP_E_OVERFLOW; 2773 *pFltOut = dblIn; 2774 return S_OK; 2775 } 2776 2777 /************************************************************************ 2778 * VarR4FromCy (OLEAUT32.72) 2779 * 2780 * Convert a VT_CY to a VT_R4. 2781 * 2782 * PARAMS 2783 * cyIn [I] Source 2784 * pFltOut [O] Destination 2785 * 2786 * RETURNS 2787 * S_OK. 2788 */ 2789 HRESULT WINAPI VarR4FromCy(CY cyIn, float *pFltOut) 2790 { 2791 *pFltOut = (double)cyIn.int64 / CY_MULTIPLIER_F; 2792 return S_OK; 2793 } 2794 2795 /************************************************************************ 2796 * VarR4FromDate (OLEAUT32.73) 2797 * 2798 * Convert a VT_DATE to a VT_R4. 2799 * 2800 * PARAMS 2801 * dateIn [I] Source 2802 * pFltOut [O] Destination 2803 * 2804 * RETURNS 2805 * Success: S_OK. 2806 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination. 2807 */ 2808 HRESULT WINAPI VarR4FromDate(DATE dateIn, float *pFltOut) 2809 { 2810 return VarR4FromR8(dateIn, pFltOut); 2811 } 2812 2813 /************************************************************************ 2814 * VarR4FromStr (OLEAUT32.74) 2815 * 2816 * Convert a VT_BSTR to a VT_R4. 2817 * 2818 * PARAMS 2819 * strIn [I] Source 2820 * lcid [I] LCID for the conversion 2821 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 2822 * pFltOut [O] Destination 2823 * 2824 * RETURNS 2825 * Success: S_OK. 2826 * Failure: E_INVALIDARG, if strIn or pFltOut is invalid. 2827 * DISP_E_TYPEMISMATCH, if the type cannot be converted 2828 */ 2829 HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, float *pFltOut) 2830 { 2831 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pFltOut, VT_R4); 2832 } 2833 2834 /************************************************************************ 2835 * VarR4FromDisp (OLEAUT32.75) 2836 * 2837 * Convert a VT_DISPATCH to a VT_R4. 2838 * 2839 * PARAMS 2840 * pdispIn [I] Source 2841 * lcid [I] LCID for conversion 2842 * pFltOut [O] Destination 2843 * 2844 * RETURNS 2845 * Success: S_OK. 2846 * Failure: E_INVALIDARG, if the source value is invalid 2847 * DISP_E_OVERFLOW, if the value will not fit in the destination 2848 * DISP_E_TYPEMISMATCH, if the type cannot be converted 2849 */ 2850 HRESULT WINAPI VarR4FromDisp(IDispatch* pdispIn, LCID lcid, float *pFltOut) 2851 { 2852 return VARIANT_FromDisp(pdispIn, lcid, pFltOut, VT_R4, 0); 2853 } 2854 2855 /************************************************************************ 2856 * VarR4FromBool (OLEAUT32.76) 2857 * 2858 * Convert a VT_BOOL to a VT_R4. 2859 * 2860 * PARAMS 2861 * boolIn [I] Source 2862 * pFltOut [O] Destination 2863 * 2864 * RETURNS 2865 * S_OK. 2866 */ 2867 HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, float *pFltOut) 2868 { 2869 return VarR4FromI2(boolIn, pFltOut); 2870 } 2871 2872 /************************************************************************ 2873 * VarR4FromI1 (OLEAUT32.213) 2874 * 2875 * Convert a VT_I1 to a VT_R4. 2876 * 2877 * PARAMS 2878 * cIn [I] Source 2879 * pFltOut [O] Destination 2880 * 2881 * RETURNS 2882 * Success: S_OK. 2883 * Failure: E_INVALIDARG, if the source value is invalid 2884 * DISP_E_OVERFLOW, if the value will not fit in the destination 2885 * DISP_E_TYPEMISMATCH, if the type cannot be converted 2886 */ 2887 HRESULT WINAPI VarR4FromI1(signed char cIn, float *pFltOut) 2888 { 2889 return _VarR4FromI1(cIn, pFltOut); 2890 } 2891 2892 /************************************************************************ 2893 * VarR4FromUI2 (OLEAUT32.214) 2894 * 2895 * Convert a VT_UI2 to a VT_R4. 2896 * 2897 * PARAMS 2898 * usIn [I] Source 2899 * pFltOut [O] Destination 2900 * 2901 * RETURNS 2902 * Success: S_OK. 2903 * Failure: E_INVALIDARG, if the source value is invalid 2904 * DISP_E_OVERFLOW, if the value will not fit in the destination 2905 * DISP_E_TYPEMISMATCH, if the type cannot be converted 2906 */ 2907 HRESULT WINAPI VarR4FromUI2(USHORT usIn, float *pFltOut) 2908 { 2909 return _VarR4FromUI2(usIn, pFltOut); 2910 } 2911 2912 /************************************************************************ 2913 * VarR4FromUI4 (OLEAUT32.215) 2914 * 2915 * Convert a VT_UI4 to a VT_R4. 2916 * 2917 * PARAMS 2918 * ulIn [I] Source 2919 * pFltOut [O] Destination 2920 * 2921 * RETURNS 2922 * Success: S_OK. 2923 * Failure: E_INVALIDARG, if the source value is invalid 2924 * DISP_E_OVERFLOW, if the value will not fit in the destination 2925 * DISP_E_TYPEMISMATCH, if the type cannot be converted 2926 */ 2927 HRESULT WINAPI VarR4FromUI4(ULONG ulIn, float *pFltOut) 2928 { 2929 return _VarR4FromUI4(ulIn, pFltOut); 2930 } 2931 2932 /************************************************************************ 2933 * VarR4FromDec (OLEAUT32.216) 2934 * 2935 * Convert a VT_DECIMAL to a VT_R4. 2936 * 2937 * PARAMS 2938 * pDecIn [I] Source 2939 * pFltOut [O] Destination 2940 * 2941 * RETURNS 2942 * Success: S_OK. 2943 * Failure: E_INVALIDARG, if the source value is invalid. 2944 */ 2945 HRESULT WINAPI VarR4FromDec(DECIMAL* pDecIn, float *pFltOut) 2946 { 2947 BYTE scale = DEC_SCALE(pDecIn); 2948 double divisor = 1.0; 2949 double highPart; 2950 2951 if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG) 2952 return E_INVALIDARG; 2953 2954 while (scale--) 2955 divisor *= 10.0; 2956 2957 if (DEC_SIGN(pDecIn)) 2958 divisor = -divisor; 2959 2960 if (DEC_HI32(pDecIn)) 2961 { 2962 highPart = (double)DEC_HI32(pDecIn) / divisor; 2963 highPart *= 4294967296.0F; 2964 highPart *= 4294967296.0F; 2965 } 2966 else 2967 highPart = 0.0; 2968 2969 *pFltOut = (double)DEC_LO64(pDecIn) / divisor + highPart; 2970 return S_OK; 2971 } 2972 2973 /************************************************************************ 2974 * VarR4FromI8 (OLEAUT32.360) 2975 * 2976 * Convert a VT_I8 to a VT_R4. 2977 * 2978 * PARAMS 2979 * ullIn [I] Source 2980 * pFltOut [O] Destination 2981 * 2982 * RETURNS 2983 * S_OK. 2984 */ 2985 HRESULT WINAPI VarR4FromI8(LONG64 llIn, float *pFltOut) 2986 { 2987 return _VarR4FromI8(llIn, pFltOut); 2988 } 2989 2990 /************************************************************************ 2991 * VarR4FromUI8 (OLEAUT32.361) 2992 * 2993 * Convert a VT_UI8 to a VT_R4. 2994 * 2995 * PARAMS 2996 * ullIn [I] Source 2997 * pFltOut [O] Destination 2998 * 2999 * RETURNS 3000 * S_OK. 3001 */ 3002 HRESULT WINAPI VarR4FromUI8(ULONG64 ullIn, float *pFltOut) 3003 { 3004 return _VarR4FromUI8(ullIn, pFltOut); 3005 } 3006 3007 /************************************************************************ 3008 * VarR4CmpR8 (OLEAUT32.316) 3009 * 3010 * Compare a VT_R4 to a VT_R8. 3011 * 3012 * PARAMS 3013 * fltLeft [I] Source 3014 * dblRight [I] Value to compare 3015 * 3016 * RETURNS 3017 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that fltLeft is less than, 3018 * equal to or greater than dblRight respectively. 3019 */ 3020 HRESULT WINAPI VarR4CmpR8(float fltLeft, double dblRight) 3021 { 3022 if (fltLeft < dblRight) 3023 return VARCMP_LT; 3024 else if (fltLeft > dblRight) 3025 return VARCMP_GT; 3026 return VARCMP_EQ; 3027 } 3028 3029 /* R8 3030 */ 3031 3032 /************************************************************************ 3033 * VarR8FromUI1 (OLEAUT32.78) 3034 * 3035 * Convert a VT_UI1 to a VT_R8. 3036 * 3037 * PARAMS 3038 * bIn [I] Source 3039 * pDblOut [O] Destination 3040 * 3041 * RETURNS 3042 * S_OK. 3043 */ 3044 HRESULT WINAPI VarR8FromUI1(BYTE bIn, double *pDblOut) 3045 { 3046 return _VarR8FromUI1(bIn, pDblOut); 3047 } 3048 3049 /************************************************************************ 3050 * VarR8FromI2 (OLEAUT32.79) 3051 * 3052 * Convert a VT_I2 to a VT_R8. 3053 * 3054 * PARAMS 3055 * sIn [I] Source 3056 * pDblOut [O] Destination 3057 * 3058 * RETURNS 3059 * S_OK. 3060 */ 3061 HRESULT WINAPI VarR8FromI2(SHORT sIn, double *pDblOut) 3062 { 3063 return _VarR8FromI2(sIn, pDblOut); 3064 } 3065 3066 /************************************************************************ 3067 * VarR8FromI4 (OLEAUT32.80) 3068 * 3069 * Convert a VT_I4 to a VT_R8. 3070 * 3071 * PARAMS 3072 * sIn [I] Source 3073 * pDblOut [O] Destination 3074 * 3075 * RETURNS 3076 * S_OK. 3077 */ 3078 HRESULT WINAPI VarR8FromI4(LONG lIn, double *pDblOut) 3079 { 3080 return _VarR8FromI4(lIn, pDblOut); 3081 } 3082 3083 /************************************************************************ 3084 * VarR8FromR4 (OLEAUT32.81) 3085 * 3086 * Convert a VT_R4 to a VT_R8. 3087 * 3088 * PARAMS 3089 * fltIn [I] Source 3090 * pDblOut [O] Destination 3091 * 3092 * RETURNS 3093 * S_OK. 3094 */ 3095 HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double *pDblOut) 3096 { 3097 return _VarR8FromR4(fltIn, pDblOut); 3098 } 3099 3100 /************************************************************************ 3101 * VarR8FromCy (OLEAUT32.82) 3102 * 3103 * Convert a VT_CY to a VT_R8. 3104 * 3105 * PARAMS 3106 * cyIn [I] Source 3107 * pDblOut [O] Destination 3108 * 3109 * RETURNS 3110 * S_OK. 3111 */ 3112 HRESULT WINAPI VarR8FromCy(CY cyIn, double *pDblOut) 3113 { 3114 return _VarR8FromCy(cyIn, pDblOut); 3115 } 3116 3117 /************************************************************************ 3118 * VarR8FromDate (OLEAUT32.83) 3119 * 3120 * Convert a VT_DATE to a VT_R8. 3121 * 3122 * PARAMS 3123 * dateIn [I] Source 3124 * pDblOut [O] Destination 3125 * 3126 * RETURNS 3127 * S_OK. 3128 */ 3129 HRESULT WINAPI VarR8FromDate(DATE dateIn, double *pDblOut) 3130 { 3131 return _VarR8FromDate(dateIn, pDblOut); 3132 } 3133 3134 /************************************************************************ 3135 * VarR8FromStr (OLEAUT32.84) 3136 * 3137 * Convert a VT_BSTR to a VT_R8. 3138 * 3139 * PARAMS 3140 * strIn [I] Source 3141 * lcid [I] LCID for the conversion 3142 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 3143 * pDblOut [O] Destination 3144 * 3145 * RETURNS 3146 * Success: S_OK. 3147 * Failure: E_INVALIDARG, if strIn or pDblOut is invalid. 3148 * DISP_E_TYPEMISMATCH, if the type cannot be converted 3149 */ 3150 HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double *pDblOut) 3151 { 3152 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDblOut, VT_R8); 3153 } 3154 3155 /************************************************************************ 3156 * VarR8FromDisp (OLEAUT32.85) 3157 * 3158 * Convert a VT_DISPATCH to a VT_R8. 3159 * 3160 * PARAMS 3161 * pdispIn [I] Source 3162 * lcid [I] LCID for conversion 3163 * pDblOut [O] Destination 3164 * 3165 * RETURNS 3166 * Success: S_OK. 3167 * Failure: E_INVALIDARG, if the source value is invalid 3168 * DISP_E_OVERFLOW, if the value will not fit in the destination 3169 * DISP_E_TYPEMISMATCH, if the type cannot be converted 3170 */ 3171 HRESULT WINAPI VarR8FromDisp(IDispatch* pdispIn, LCID lcid, double *pDblOut) 3172 { 3173 return VARIANT_FromDisp(pdispIn, lcid, pDblOut, VT_R8, 0); 3174 } 3175 3176 /************************************************************************ 3177 * VarR8FromBool (OLEAUT32.86) 3178 * 3179 * Convert a VT_BOOL to a VT_R8. 3180 * 3181 * PARAMS 3182 * boolIn [I] Source 3183 * pDblOut [O] Destination 3184 * 3185 * RETURNS 3186 * S_OK. 3187 */ 3188 HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double *pDblOut) 3189 { 3190 return VarR8FromI2(boolIn, pDblOut); 3191 } 3192 3193 /************************************************************************ 3194 * VarR8FromI1 (OLEAUT32.217) 3195 * 3196 * Convert a VT_I1 to a VT_R8. 3197 * 3198 * PARAMS 3199 * cIn [I] Source 3200 * pDblOut [O] Destination 3201 * 3202 * RETURNS 3203 * Success: S_OK. 3204 * Failure: E_INVALIDARG, if the source value is invalid 3205 * DISP_E_OVERFLOW, if the value will not fit in the destination 3206 * DISP_E_TYPEMISMATCH, if the type cannot be converted 3207 */ 3208 HRESULT WINAPI VarR8FromI1(signed char cIn, double *pDblOut) 3209 { 3210 return _VarR8FromI1(cIn, pDblOut); 3211 } 3212 3213 /************************************************************************ 3214 * VarR8FromUI2 (OLEAUT32.218) 3215 * 3216 * Convert a VT_UI2 to a VT_R8. 3217 * 3218 * PARAMS 3219 * usIn [I] Source 3220 * pDblOut [O] Destination 3221 * 3222 * RETURNS 3223 * Success: S_OK. 3224 * Failure: E_INVALIDARG, if the source value is invalid 3225 * DISP_E_OVERFLOW, if the value will not fit in the destination 3226 * DISP_E_TYPEMISMATCH, if the type cannot be converted 3227 */ 3228 HRESULT WINAPI VarR8FromUI2(USHORT usIn, double *pDblOut) 3229 { 3230 return _VarR8FromUI2(usIn, pDblOut); 3231 } 3232 3233 /************************************************************************ 3234 * VarR8FromUI4 (OLEAUT32.219) 3235 * 3236 * Convert a VT_UI4 to a VT_R8. 3237 * 3238 * PARAMS 3239 * ulIn [I] Source 3240 * pDblOut [O] Destination 3241 * 3242 * RETURNS 3243 * Success: S_OK. 3244 * Failure: E_INVALIDARG, if the source value is invalid 3245 * DISP_E_OVERFLOW, if the value will not fit in the destination 3246 * DISP_E_TYPEMISMATCH, if the type cannot be converted 3247 */ 3248 HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double *pDblOut) 3249 { 3250 return _VarR8FromUI4(ulIn, pDblOut); 3251 } 3252 3253 /************************************************************************ 3254 * VarR8FromDec (OLEAUT32.220) 3255 * 3256 * Convert a VT_DECIMAL to a VT_R8. 3257 * 3258 * PARAMS 3259 * pDecIn [I] Source 3260 * pDblOut [O] Destination 3261 * 3262 * RETURNS 3263 * Success: S_OK. 3264 * Failure: E_INVALIDARG, if the source value is invalid. 3265 */ 3266 HRESULT WINAPI VarR8FromDec(const DECIMAL* pDecIn, double *pDblOut) 3267 { 3268 BYTE scale = DEC_SCALE(pDecIn); 3269 double divisor = 1.0, highPart; 3270 3271 if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG) 3272 return E_INVALIDARG; 3273 3274 while (scale--) 3275 divisor *= 10; 3276 3277 if (DEC_SIGN(pDecIn)) 3278 divisor = -divisor; 3279 3280 if (DEC_HI32(pDecIn)) 3281 { 3282 highPart = (double)DEC_HI32(pDecIn) / divisor; 3283 highPart *= 4294967296.0F; 3284 highPart *= 4294967296.0F; 3285 } 3286 else 3287 highPart = 0.0; 3288 3289 *pDblOut = (double)DEC_LO64(pDecIn) / divisor + highPart; 3290 return S_OK; 3291 } 3292 3293 /************************************************************************ 3294 * VarR8FromI8 (OLEAUT32.362) 3295 * 3296 * Convert a VT_I8 to a VT_R8. 3297 * 3298 * PARAMS 3299 * ullIn [I] Source 3300 * pDblOut [O] Destination 3301 * 3302 * RETURNS 3303 * S_OK. 3304 */ 3305 HRESULT WINAPI VarR8FromI8(LONG64 llIn, double *pDblOut) 3306 { 3307 return _VarR8FromI8(llIn, pDblOut); 3308 } 3309 3310 /************************************************************************ 3311 * VarR8FromUI8 (OLEAUT32.363) 3312 * 3313 * Convert a VT_UI8 to a VT_R8. 3314 * 3315 * PARAMS 3316 * ullIn [I] Source 3317 * pDblOut [O] Destination 3318 * 3319 * RETURNS 3320 * S_OK. 3321 */ 3322 HRESULT WINAPI VarR8FromUI8(ULONG64 ullIn, double *pDblOut) 3323 { 3324 return _VarR8FromUI8(ullIn, pDblOut); 3325 } 3326 3327 /************************************************************************ 3328 * VarR8Pow (OLEAUT32.315) 3329 * 3330 * Raise a VT_R8 to a power. 3331 * 3332 * PARAMS 3333 * dblLeft [I] Source 3334 * dblPow [I] Power to raise dblLeft by 3335 * pDblOut [O] Destination 3336 * 3337 * RETURNS 3338 * S_OK. pDblOut contains dblLeft to the power of dblRight. 3339 */ 3340 HRESULT WINAPI VarR8Pow(double dblLeft, double dblPow, double *pDblOut) 3341 { 3342 *pDblOut = pow(dblLeft, dblPow); 3343 return S_OK; 3344 } 3345 3346 /************************************************************************ 3347 * VarR8Round (OLEAUT32.317) 3348 * 3349 * Round a VT_R8 to a given number of decimal points. 3350 * 3351 * PARAMS 3352 * dblIn [I] Source 3353 * nDig [I] Number of decimal points to round to 3354 * pDblOut [O] Destination for rounded number 3355 * 3356 * RETURNS 3357 * Success: S_OK. pDblOut is rounded to nDig digits. 3358 * Failure: E_INVALIDARG, if cDecimals is less than 0. 3359 * 3360 * NOTES 3361 * The native version of this function rounds using the internal 3362 * binary representation of the number. Wine uses the dutch rounding 3363 * convention, so therefore small differences can occur in the value returned. 3364 * MSDN says that you should use your own rounding function if you want 3365 * rounding to be predictable in your application. 3366 */ 3367 HRESULT WINAPI VarR8Round(double dblIn, int nDig, double *pDblOut) 3368 { 3369 double scale, whole, fract; 3370 3371 if (nDig < 0) 3372 return E_INVALIDARG; 3373 3374 scale = pow(10.0, nDig); 3375 3376 dblIn *= scale; 3377 whole = dblIn < 0 ? ceil(dblIn) : floor(dblIn); 3378 fract = dblIn - whole; 3379 3380 if (fract > 0.5) 3381 dblIn = whole + 1.0; 3382 else if (fract == 0.5) 3383 dblIn = whole + fmod(whole, 2.0); 3384 else if (fract >= 0.0) 3385 dblIn = whole; 3386 else if (fract == -0.5) 3387 dblIn = whole - fmod(whole, 2.0); 3388 else if (fract > -0.5) 3389 dblIn = whole; 3390 else 3391 dblIn = whole - 1.0; 3392 3393 *pDblOut = dblIn / scale; 3394 return S_OK; 3395 } 3396 3397 /* CY 3398 */ 3399 3400 /* Powers of 10 from 0..4 D.P. */ 3401 static const int CY_Divisors[5] = { CY_MULTIPLIER/10000, CY_MULTIPLIER/1000, 3402 CY_MULTIPLIER/100, CY_MULTIPLIER/10, CY_MULTIPLIER }; 3403 3404 /************************************************************************ 3405 * VarCyFromUI1 (OLEAUT32.98) 3406 * 3407 * Convert a VT_UI1 to a VT_CY. 3408 * 3409 * PARAMS 3410 * bIn [I] Source 3411 * pCyOut [O] Destination 3412 * 3413 * RETURNS 3414 * Success: S_OK. 3415 * Failure: E_INVALIDARG, if the source value is invalid 3416 * DISP_E_OVERFLOW, if the value will not fit in the destination 3417 * DISP_E_TYPEMISMATCH, if the type cannot be converted 3418 */ 3419 HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pCyOut) 3420 { 3421 pCyOut->int64 = (ULONG64)bIn * CY_MULTIPLIER; 3422 return S_OK; 3423 } 3424 3425 /************************************************************************ 3426 * VarCyFromI2 (OLEAUT32.99) 3427 * 3428 * Convert a VT_I2 to a VT_CY. 3429 * 3430 * PARAMS 3431 * sIn [I] Source 3432 * pCyOut [O] Destination 3433 * 3434 * RETURNS 3435 * Success: S_OK. 3436 * Failure: E_INVALIDARG, if the source value is invalid 3437 * DISP_E_OVERFLOW, if the value will not fit in the destination 3438 * DISP_E_TYPEMISMATCH, if the type cannot be converted 3439 */ 3440 HRESULT WINAPI VarCyFromI2(SHORT sIn, CY* pCyOut) 3441 { 3442 pCyOut->int64 = (LONG64)sIn * CY_MULTIPLIER; 3443 return S_OK; 3444 } 3445 3446 /************************************************************************ 3447 * VarCyFromI4 (OLEAUT32.100) 3448 * 3449 * Convert a VT_I4 to a VT_CY. 3450 * 3451 * PARAMS 3452 * sIn [I] Source 3453 * pCyOut [O] Destination 3454 * 3455 * RETURNS 3456 * Success: S_OK. 3457 * Failure: E_INVALIDARG, if the source value is invalid 3458 * DISP_E_OVERFLOW, if the value will not fit in the destination 3459 * DISP_E_TYPEMISMATCH, if the type cannot be converted 3460 */ 3461 HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pCyOut) 3462 { 3463 pCyOut->int64 = (LONG64)lIn * CY_MULTIPLIER; 3464 return S_OK; 3465 } 3466 3467 /************************************************************************ 3468 * VarCyFromR4 (OLEAUT32.101) 3469 * 3470 * Convert a VT_R4 to a VT_CY. 3471 * 3472 * PARAMS 3473 * fltIn [I] Source 3474 * pCyOut [O] Destination 3475 * 3476 * RETURNS 3477 * Success: S_OK. 3478 * Failure: E_INVALIDARG, if the source value is invalid 3479 * DISP_E_OVERFLOW, if the value will not fit in the destination 3480 * DISP_E_TYPEMISMATCH, if the type cannot be converted 3481 */ 3482 HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pCyOut) 3483 { 3484 return VarCyFromR8(fltIn, pCyOut); 3485 } 3486 3487 /************************************************************************ 3488 * VarCyFromR8 (OLEAUT32.102) 3489 * 3490 * Convert a VT_R8 to a VT_CY. 3491 * 3492 * PARAMS 3493 * dblIn [I] Source 3494 * pCyOut [O] Destination 3495 * 3496 * RETURNS 3497 * Success: S_OK. 3498 * Failure: E_INVALIDARG, if the source value is invalid 3499 * DISP_E_OVERFLOW, if the value will not fit in the destination 3500 * DISP_E_TYPEMISMATCH, if the type cannot be converted 3501 */ 3502 HRESULT WINAPI VarCyFromR8(double dblIn, CY* pCyOut) 3503 { 3504 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) 3505 /* This code gives identical results to Win32 on Intel. 3506 * Here we use fp exceptions to catch overflows when storing the value. 3507 */ 3508 static const unsigned short r8_fpcontrol = 0x137f; 3509 static const double r8_multiplier = CY_MULTIPLIER_F; 3510 unsigned short old_fpcontrol, result_fpstatus; 3511 3512 /* Clear exceptions, save the old fp state and load the new state */ 3513 __asm__ __volatile__( "fnclex" ); 3514 __asm__ __volatile__( "fstcw %0" : "=m" (old_fpcontrol) : ); 3515 __asm__ __volatile__( "fldcw %0" : : "m" (r8_fpcontrol) ); 3516 /* Perform the conversion. */ 3517 __asm__ __volatile__( "fldl %0" : : "m" (dblIn) ); 3518 __asm__ __volatile__( "fmull %0" : : "m" (r8_multiplier) ); 3519 __asm__ __volatile__( "fistpll %0" : : "m" (*pCyOut) ); 3520 /* Save the resulting fp state, load the old state and clear exceptions */ 3521 __asm__ __volatile__( "fstsw %0" : "=m" (result_fpstatus) : ); 3522 __asm__ __volatile__( "fnclex" ); 3523 __asm__ __volatile__( "fldcw %0" : : "m" (old_fpcontrol) ); 3524 3525 if (result_fpstatus & 0x9) /* Overflow | Invalid */ 3526 return DISP_E_OVERFLOW; 3527 #else 3528 /* This version produces slightly different results for boundary cases */ 3529 if (dblIn < -922337203685477.5807 || dblIn >= 922337203685477.5807) 3530 return DISP_E_OVERFLOW; 3531 dblIn *= CY_MULTIPLIER_F; 3532 VARIANT_DutchRound(LONG64, dblIn, pCyOut->int64); 3533 #endif 3534 return S_OK; 3535 } 3536 3537 /************************************************************************ 3538 * VarCyFromDate (OLEAUT32.103) 3539 * 3540 * Convert a VT_DATE to a VT_CY. 3541 * 3542 * PARAMS 3543 * dateIn [I] Source 3544 * pCyOut [O] Destination 3545 * 3546 * RETURNS 3547 * Success: S_OK. 3548 * Failure: E_INVALIDARG, if the source value is invalid 3549 * DISP_E_OVERFLOW, if the value will not fit in the destination 3550 * DISP_E_TYPEMISMATCH, if the type cannot be converted 3551 */ 3552 HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pCyOut) 3553 { 3554 return VarCyFromR8(dateIn, pCyOut); 3555 } 3556 3557 /************************************************************************ 3558 * VarCyFromStr (OLEAUT32.104) 3559 * 3560 * Convert a VT_BSTR to a VT_CY. 3561 * 3562 * PARAMS 3563 * strIn [I] Source 3564 * lcid [I] LCID for the conversion 3565 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 3566 * pCyOut [O] Destination 3567 * 3568 * RETURNS 3569 * Success: S_OK. 3570 * Failure: E_INVALIDARG, if the source value is invalid 3571 * DISP_E_OVERFLOW, if the value will not fit in the destination 3572 * DISP_E_TYPEMISMATCH, if the type cannot be converted 3573 */ 3574 HRESULT WINAPI VarCyFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, CY* pCyOut) 3575 { 3576 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pCyOut, VT_CY); 3577 } 3578 3579 /************************************************************************ 3580 * VarCyFromDisp (OLEAUT32.105) 3581 * 3582 * Convert a VT_DISPATCH to a VT_CY. 3583 * 3584 * PARAMS 3585 * pdispIn [I] Source 3586 * lcid [I] LCID for conversion 3587 * pCyOut [O] Destination 3588 * 3589 * RETURNS 3590 * Success: S_OK. 3591 * Failure: E_INVALIDARG, if the source value is invalid 3592 * DISP_E_OVERFLOW, if the value will not fit in the destination 3593 * DISP_E_TYPEMISMATCH, if the type cannot be converted 3594 */ 3595 HRESULT WINAPI VarCyFromDisp(IDispatch* pdispIn, LCID lcid, CY* pCyOut) 3596 { 3597 return VARIANT_FromDisp(pdispIn, lcid, pCyOut, VT_CY, 0); 3598 } 3599 3600 /************************************************************************ 3601 * VarCyFromBool (OLEAUT32.106) 3602 * 3603 * Convert a VT_BOOL to a VT_CY. 3604 * 3605 * PARAMS 3606 * boolIn [I] Source 3607 * pCyOut [O] Destination 3608 * 3609 * RETURNS 3610 * Success: S_OK. 3611 * Failure: E_INVALIDARG, if the source value is invalid 3612 * DISP_E_OVERFLOW, if the value will not fit in the destination 3613 * DISP_E_TYPEMISMATCH, if the type cannot be converted 3614 * 3615 * NOTES 3616 * While the sign of the boolean is stored in the currency, the value is 3617 * converted to either 0 or 1. 3618 */ 3619 HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pCyOut) 3620 { 3621 pCyOut->int64 = (LONG64)boolIn * CY_MULTIPLIER; 3622 return S_OK; 3623 } 3624 3625 /************************************************************************ 3626 * VarCyFromI1 (OLEAUT32.225) 3627 * 3628 * Convert a VT_I1 to a VT_CY. 3629 * 3630 * PARAMS 3631 * cIn [I] Source 3632 * pCyOut [O] Destination 3633 * 3634 * RETURNS 3635 * Success: S_OK. 3636 * Failure: E_INVALIDARG, if the source value is invalid 3637 * DISP_E_OVERFLOW, if the value will not fit in the destination 3638 * DISP_E_TYPEMISMATCH, if the type cannot be converted 3639 */ 3640 HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pCyOut) 3641 { 3642 pCyOut->int64 = (LONG64)cIn * CY_MULTIPLIER; 3643 return S_OK; 3644 } 3645 3646 /************************************************************************ 3647 * VarCyFromUI2 (OLEAUT32.226) 3648 * 3649 * Convert a VT_UI2 to a VT_CY. 3650 * 3651 * PARAMS 3652 * usIn [I] Source 3653 * pCyOut [O] Destination 3654 * 3655 * RETURNS 3656 * Success: S_OK. 3657 * Failure: E_INVALIDARG, if the source value is invalid 3658 * DISP_E_OVERFLOW, if the value will not fit in the destination 3659 * DISP_E_TYPEMISMATCH, if the type cannot be converted 3660 */ 3661 HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pCyOut) 3662 { 3663 pCyOut->int64 = (ULONG64)usIn * CY_MULTIPLIER; 3664 return S_OK; 3665 } 3666 3667 /************************************************************************ 3668 * VarCyFromUI4 (OLEAUT32.227) 3669 * 3670 * Convert a VT_UI4 to a VT_CY. 3671 * 3672 * PARAMS 3673 * ulIn [I] Source 3674 * pCyOut [O] Destination 3675 * 3676 * RETURNS 3677 * Success: S_OK. 3678 * Failure: E_INVALIDARG, if the source value is invalid 3679 * DISP_E_OVERFLOW, if the value will not fit in the destination 3680 * DISP_E_TYPEMISMATCH, if the type cannot be converted 3681 */ 3682 HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pCyOut) 3683 { 3684 pCyOut->int64 = (ULONG64)ulIn * CY_MULTIPLIER; 3685 return S_OK; 3686 } 3687 3688 /************************************************************************ 3689 * VarCyFromDec (OLEAUT32.228) 3690 * 3691 * Convert a VT_DECIMAL to a VT_CY. 3692 * 3693 * PARAMS 3694 * pdecIn [I] Source 3695 * pCyOut [O] Destination 3696 * 3697 * RETURNS 3698 * Success: S_OK. 3699 * Failure: E_INVALIDARG, if the source value is invalid 3700 * DISP_E_OVERFLOW, if the value will not fit in the destination 3701 * DISP_E_TYPEMISMATCH, if the type cannot be converted 3702 */ 3703 HRESULT WINAPI VarCyFromDec(DECIMAL* pdecIn, CY* pCyOut) 3704 { 3705 DECIMAL rounded; 3706 HRESULT hRet; 3707 3708 hRet = VarDecRound(pdecIn, 4, &rounded); 3709 3710 if (SUCCEEDED(hRet)) 3711 { 3712 double d; 3713 3714 if (DEC_HI32(&rounded)) 3715 return DISP_E_OVERFLOW; 3716 3717 /* Note: Without the casts this promotes to int64 which loses precision */ 3718 d = (double)DEC_LO64(&rounded) / (double)CY_Divisors[DEC_SCALE(&rounded)]; 3719 if (DEC_SIGN(&rounded)) 3720 d = -d; 3721 return VarCyFromR8(d, pCyOut); 3722 } 3723 return hRet; 3724 } 3725 3726 /************************************************************************ 3727 * VarCyFromI8 (OLEAUT32.366) 3728 * 3729 * Convert a VT_I8 to a VT_CY. 3730 * 3731 * PARAMS 3732 * ullIn [I] Source 3733 * pCyOut [O] Destination 3734 * 3735 * RETURNS 3736 * Success: S_OK. 3737 * Failure: E_INVALIDARG, if the source value is invalid 3738 * DISP_E_OVERFLOW, if the value will not fit in the destination 3739 * DISP_E_TYPEMISMATCH, if the type cannot be converted 3740 */ 3741 HRESULT WINAPI VarCyFromI8(LONG64 llIn, CY* pCyOut) 3742 { 3743 if (llIn <= (I8_MIN/CY_MULTIPLIER) || llIn >= (I8_MAX/CY_MULTIPLIER)) return DISP_E_OVERFLOW; 3744 pCyOut->int64 = llIn * CY_MULTIPLIER; 3745 return S_OK; 3746 } 3747 3748 /************************************************************************ 3749 * VarCyFromUI8 (OLEAUT32.375) 3750 * 3751 * Convert a VT_UI8 to a VT_CY. 3752 * 3753 * PARAMS 3754 * ullIn [I] Source 3755 * pCyOut [O] Destination 3756 * 3757 * RETURNS 3758 * Success: S_OK. 3759 * Failure: E_INVALIDARG, if the source value is invalid 3760 * DISP_E_OVERFLOW, if the value will not fit in the destination 3761 * DISP_E_TYPEMISMATCH, if the type cannot be converted 3762 */ 3763 HRESULT WINAPI VarCyFromUI8(ULONG64 ullIn, CY* pCyOut) 3764 { 3765 if (ullIn > (I8_MAX/CY_MULTIPLIER)) return DISP_E_OVERFLOW; 3766 pCyOut->int64 = ullIn * CY_MULTIPLIER; 3767 return S_OK; 3768 } 3769 3770 /************************************************************************ 3771 * VarCyAdd (OLEAUT32.299) 3772 * 3773 * Add one CY to another. 3774 * 3775 * PARAMS 3776 * cyLeft [I] Source 3777 * cyRight [I] Value to add 3778 * pCyOut [O] Destination 3779 * 3780 * RETURNS 3781 * Success: S_OK. 3782 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 3783 */ 3784 HRESULT WINAPI VarCyAdd(const CY cyLeft, const CY cyRight, CY* pCyOut) 3785 { 3786 double l,r; 3787 _VarR8FromCy(cyLeft, &l); 3788 _VarR8FromCy(cyRight, &r); 3789 l = l + r; 3790 return VarCyFromR8(l, pCyOut); 3791 } 3792 3793 /************************************************************************ 3794 * VarCyMul (OLEAUT32.303) 3795 * 3796 * Multiply one CY by another. 3797 * 3798 * PARAMS 3799 * cyLeft [I] Source 3800 * cyRight [I] Value to multiply by 3801 * pCyOut [O] Destination 3802 * 3803 * RETURNS 3804 * Success: S_OK. 3805 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 3806 */ 3807 HRESULT WINAPI VarCyMul(const CY cyLeft, const CY cyRight, CY* pCyOut) 3808 { 3809 double l,r; 3810 _VarR8FromCy(cyLeft, &l); 3811 _VarR8FromCy(cyRight, &r); 3812 l = l * r; 3813 return VarCyFromR8(l, pCyOut); 3814 } 3815 3816 /************************************************************************ 3817 * VarCyMulI4 (OLEAUT32.304) 3818 * 3819 * Multiply one CY by a VT_I4. 3820 * 3821 * PARAMS 3822 * cyLeft [I] Source 3823 * lRight [I] Value to multiply by 3824 * pCyOut [O] Destination 3825 * 3826 * RETURNS 3827 * Success: S_OK. 3828 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 3829 */ 3830 HRESULT WINAPI VarCyMulI4(const CY cyLeft, LONG lRight, CY* pCyOut) 3831 { 3832 double d; 3833 3834 _VarR8FromCy(cyLeft, &d); 3835 d = d * lRight; 3836 return VarCyFromR8(d, pCyOut); 3837 } 3838 3839 /************************************************************************ 3840 * VarCySub (OLEAUT32.305) 3841 * 3842 * Subtract one CY from another. 3843 * 3844 * PARAMS 3845 * cyLeft [I] Source 3846 * cyRight [I] Value to subtract 3847 * pCyOut [O] Destination 3848 * 3849 * RETURNS 3850 * Success: S_OK. 3851 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 3852 */ 3853 HRESULT WINAPI VarCySub(const CY cyLeft, const CY cyRight, CY* pCyOut) 3854 { 3855 double l,r; 3856 _VarR8FromCy(cyLeft, &l); 3857 _VarR8FromCy(cyRight, &r); 3858 l = l - r; 3859 return VarCyFromR8(l, pCyOut); 3860 } 3861 3862 /************************************************************************ 3863 * VarCyAbs (OLEAUT32.306) 3864 * 3865 * Convert a VT_CY into its absolute value. 3866 * 3867 * PARAMS 3868 * cyIn [I] Source 3869 * pCyOut [O] Destination 3870 * 3871 * RETURNS 3872 * Success: S_OK. pCyOut contains the absolute value. 3873 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 3874 */ 3875 HRESULT WINAPI VarCyAbs(const CY cyIn, CY* pCyOut) 3876 { 3877 if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo) 3878 return DISP_E_OVERFLOW; 3879 3880 pCyOut->int64 = cyIn.int64 < 0 ? -cyIn.int64 : cyIn.int64; 3881 return S_OK; 3882 } 3883 3884 /************************************************************************ 3885 * VarCyFix (OLEAUT32.307) 3886 * 3887 * Return the integer part of a VT_CY. 3888 * 3889 * PARAMS 3890 * cyIn [I] Source 3891 * pCyOut [O] Destination 3892 * 3893 * RETURNS 3894 * Success: S_OK. 3895 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 3896 * 3897 * NOTES 3898 * - The difference between this function and VarCyInt() is that VarCyInt() rounds 3899 * negative numbers away from 0, while this function rounds them towards zero. 3900 */ 3901 HRESULT WINAPI VarCyFix(const CY cyIn, CY* pCyOut) 3902 { 3903 pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER; 3904 pCyOut->int64 *= CY_MULTIPLIER; 3905 return S_OK; 3906 } 3907 3908 /************************************************************************ 3909 * VarCyInt (OLEAUT32.308) 3910 * 3911 * Return the integer part of a VT_CY. 3912 * 3913 * PARAMS 3914 * cyIn [I] Source 3915 * pCyOut [O] Destination 3916 * 3917 * RETURNS 3918 * Success: S_OK. 3919 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 3920 * 3921 * NOTES 3922 * - The difference between this function and VarCyFix() is that VarCyFix() rounds 3923 * negative numbers towards 0, while this function rounds them away from zero. 3924 */ 3925 HRESULT WINAPI VarCyInt(const CY cyIn, CY* pCyOut) 3926 { 3927 pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER; 3928 pCyOut->int64 *= CY_MULTIPLIER; 3929 3930 if (cyIn.int64 < 0 && cyIn.int64 % CY_MULTIPLIER != 0) 3931 { 3932 pCyOut->int64 -= CY_MULTIPLIER; 3933 } 3934 return S_OK; 3935 } 3936 3937 /************************************************************************ 3938 * VarCyNeg (OLEAUT32.309) 3939 * 3940 * Change the sign of a VT_CY. 3941 * 3942 * PARAMS 3943 * cyIn [I] Source 3944 * pCyOut [O] Destination 3945 * 3946 * RETURNS 3947 * Success: S_OK. 3948 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 3949 */ 3950 HRESULT WINAPI VarCyNeg(const CY cyIn, CY* pCyOut) 3951 { 3952 if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo) 3953 return DISP_E_OVERFLOW; 3954 3955 pCyOut->int64 = -cyIn.int64; 3956 return S_OK; 3957 } 3958 3959 /************************************************************************ 3960 * VarCyRound (OLEAUT32.310) 3961 * 3962 * Change the precision of a VT_CY. 3963 * 3964 * PARAMS 3965 * cyIn [I] Source 3966 * cDecimals [I] New number of decimals to keep 3967 * pCyOut [O] Destination 3968 * 3969 * RETURNS 3970 * Success: S_OK. 3971 * Failure: E_INVALIDARG, if cDecimals is less than 0. 3972 */ 3973 HRESULT WINAPI VarCyRound(const CY cyIn, int cDecimals, CY* pCyOut) 3974 { 3975 if (cDecimals < 0) 3976 return E_INVALIDARG; 3977 3978 if (cDecimals > 3) 3979 { 3980 /* Rounding to more precision than we have */ 3981 *pCyOut = cyIn; 3982 return S_OK; 3983 } 3984 else 3985 { 3986 double d, div = CY_Divisors[cDecimals]; 3987 3988 _VarR8FromCy(cyIn, &d); 3989 d = d * div; 3990 VARIANT_DutchRound(LONGLONG, d, pCyOut->int64); 3991 d = (double)pCyOut->int64 / div * CY_MULTIPLIER_F; 3992 VARIANT_DutchRound(LONGLONG, d, pCyOut->int64); 3993 return S_OK; 3994 } 3995 } 3996 3997 /************************************************************************ 3998 * VarCyCmp (OLEAUT32.311) 3999 * 4000 * Compare two VT_CY values. 4001 * 4002 * PARAMS 4003 * cyLeft [I] Source 4004 * cyRight [I] Value to compare 4005 * 4006 * RETURNS 4007 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that the value to 4008 * compare is less, equal or greater than source respectively. 4009 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison 4010 */ 4011 HRESULT WINAPI VarCyCmp(const CY cyLeft, const CY cyRight) 4012 { 4013 HRESULT hRet; 4014 CY result; 4015 4016 /* Subtract right from left, and compare the result to 0 */ 4017 hRet = VarCySub(cyLeft, cyRight, &result); 4018 4019 if (SUCCEEDED(hRet)) 4020 { 4021 if (result.int64 < 0) 4022 hRet = (HRESULT)VARCMP_LT; 4023 else if (result.int64 > 0) 4024 hRet = (HRESULT)VARCMP_GT; 4025 else 4026 hRet = (HRESULT)VARCMP_EQ; 4027 } 4028 return hRet; 4029 } 4030 4031 /************************************************************************ 4032 * VarCyCmpR8 (OLEAUT32.312) 4033 * 4034 * Compare a VT_CY to a double 4035 * 4036 * PARAMS 4037 * cyLeft [I] Currency Source 4038 * dblRight [I] double to compare to cyLeft 4039 * 4040 * RETURNS 4041 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight is 4042 * less than, equal to or greater than cyLeft respectively. 4043 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison 4044 */ 4045 HRESULT WINAPI VarCyCmpR8(const CY cyLeft, double dblRight) 4046 { 4047 HRESULT hRet; 4048 CY cyRight; 4049 4050 hRet = VarCyFromR8(dblRight, &cyRight); 4051 4052 if (SUCCEEDED(hRet)) 4053 hRet = VarCyCmp(cyLeft, cyRight); 4054 4055 return hRet; 4056 } 4057 4058 /************************************************************************ 4059 * VarCyMulI8 (OLEAUT32.329) 4060 * 4061 * Multiply a VT_CY by a VT_I8. 4062 * 4063 * PARAMS 4064 * cyLeft [I] Source 4065 * llRight [I] Value to multiply by 4066 * pCyOut [O] Destination 4067 * 4068 * RETURNS 4069 * Success: S_OK. 4070 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 4071 */ 4072 HRESULT WINAPI VarCyMulI8(const CY cyLeft, LONG64 llRight, CY* pCyOut) 4073 { 4074 double d; 4075 4076 _VarR8FromCy(cyLeft, &d); 4077 d = d * (double)llRight; 4078 return VarCyFromR8(d, pCyOut); 4079 } 4080 4081 /* DECIMAL 4082 */ 4083 4084 /************************************************************************ 4085 * VarDecFromUI1 (OLEAUT32.190) 4086 * 4087 * Convert a VT_UI1 to a DECIMAL. 4088 * 4089 * PARAMS 4090 * bIn [I] Source 4091 * pDecOut [O] Destination 4092 * 4093 * RETURNS 4094 * S_OK. 4095 */ 4096 HRESULT WINAPI VarDecFromUI1(BYTE bIn, DECIMAL* pDecOut) 4097 { 4098 return VarDecFromUI4(bIn, pDecOut); 4099 } 4100 4101 /************************************************************************ 4102 * VarDecFromI2 (OLEAUT32.191) 4103 * 4104 * Convert a VT_I2 to a DECIMAL. 4105 * 4106 * PARAMS 4107 * sIn [I] Source 4108 * pDecOut [O] Destination 4109 * 4110 * RETURNS 4111 * S_OK. 4112 */ 4113 HRESULT WINAPI VarDecFromI2(SHORT sIn, DECIMAL* pDecOut) 4114 { 4115 return VarDecFromI4(sIn, pDecOut); 4116 } 4117 4118 /************************************************************************ 4119 * VarDecFromI4 (OLEAUT32.192) 4120 * 4121 * Convert a VT_I4 to a DECIMAL. 4122 * 4123 * PARAMS 4124 * sIn [I] Source 4125 * pDecOut [O] Destination 4126 * 4127 * RETURNS 4128 * S_OK. 4129 */ 4130 HRESULT WINAPI VarDecFromI4(LONG lIn, DECIMAL* pDecOut) 4131 { 4132 DEC_HI32(pDecOut) = 0; 4133 DEC_MID32(pDecOut) = 0; 4134 4135 if (lIn < 0) 4136 { 4137 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0); 4138 DEC_LO32(pDecOut) = -lIn; 4139 } 4140 else 4141 { 4142 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0); 4143 DEC_LO32(pDecOut) = lIn; 4144 } 4145 return S_OK; 4146 } 4147 4148 /* internal representation of the value stored in a DECIMAL. The bytes are 4149 stored from LSB at index 0 to MSB at index 11 4150 */ 4151 typedef struct DECIMAL_internal 4152 { 4153 DWORD bitsnum[3]; /* 96 significant bits, unsigned */ 4154 unsigned char scale; /* number scaled * 10 ^ -(scale) */ 4155 unsigned int sign : 1; /* 0 - positive, 1 - negative */ 4156 } VARIANT_DI; 4157 4158 static HRESULT VARIANT_DI_FromR4(float source, VARIANT_DI * dest); 4159 static HRESULT VARIANT_DI_FromR8(double source, VARIANT_DI * dest); 4160 static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to); 4161 static void VARIANT_DecFromDI(const VARIANT_DI * from, DECIMAL * to); 4162 static unsigned char VARIANT_int_divbychar(DWORD * p, unsigned int n, unsigned char divisor); 4163 static BOOL VARIANT_int_iszero(const DWORD * p, unsigned int n); 4164 4165 /************************************************************************ 4166 * VarDecFromR4 (OLEAUT32.193) 4167 * 4168 * Convert a VT_R4 to a DECIMAL. 4169 * 4170 * PARAMS 4171 * fltIn [I] Source 4172 * pDecOut [O] Destination 4173 * 4174 * RETURNS 4175 * S_OK. 4176 */ 4177 HRESULT WINAPI VarDecFromR4(FLOAT fltIn, DECIMAL* pDecOut) 4178 { 4179 VARIANT_DI di; 4180 HRESULT hres; 4181 4182 hres = VARIANT_DI_FromR4(fltIn, &di); 4183 if (hres == S_OK) VARIANT_DecFromDI(&di, pDecOut); 4184 return hres; 4185 } 4186 4187 /************************************************************************ 4188 * VarDecFromR8 (OLEAUT32.194) 4189 * 4190 * Convert a VT_R8 to a DECIMAL. 4191 * 4192 * PARAMS 4193 * dblIn [I] Source 4194 * pDecOut [O] Destination 4195 * 4196 * RETURNS 4197 * S_OK. 4198 */ 4199 HRESULT WINAPI VarDecFromR8(double dblIn, DECIMAL* pDecOut) 4200 { 4201 VARIANT_DI di; 4202 HRESULT hres; 4203 4204 hres = VARIANT_DI_FromR8(dblIn, &di); 4205 if (hres == S_OK) VARIANT_DecFromDI(&di, pDecOut); 4206 return hres; 4207 } 4208 4209 /************************************************************************ 4210 * VarDecFromDate (OLEAUT32.195) 4211 * 4212 * Convert a VT_DATE to a DECIMAL. 4213 * 4214 * PARAMS 4215 * dateIn [I] Source 4216 * pDecOut [O] Destination 4217 * 4218 * RETURNS 4219 * S_OK. 4220 */ 4221 HRESULT WINAPI VarDecFromDate(DATE dateIn, DECIMAL* pDecOut) 4222 { 4223 return VarDecFromR8(dateIn, pDecOut); 4224 } 4225 4226 /************************************************************************ 4227 * VarDecFromCy (OLEAUT32.196) 4228 * 4229 * Convert a VT_CY to a DECIMAL. 4230 * 4231 * PARAMS 4232 * cyIn [I] Source 4233 * pDecOut [O] Destination 4234 * 4235 * RETURNS 4236 * S_OK. 4237 */ 4238 HRESULT WINAPI VarDecFromCy(CY cyIn, DECIMAL* pDecOut) 4239 { 4240 DEC_HI32(pDecOut) = 0; 4241 4242 /* Note: This assumes 2s complement integer representation */ 4243 if (cyIn.s.Hi & 0x80000000) 4244 { 4245 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,4); 4246 DEC_LO64(pDecOut) = -cyIn.int64; 4247 } 4248 else 4249 { 4250 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,4); 4251 DEC_MID32(pDecOut) = cyIn.s.Hi; 4252 DEC_LO32(pDecOut) = cyIn.s.Lo; 4253 } 4254 return S_OK; 4255 } 4256 4257 /************************************************************************ 4258 * VarDecFromStr (OLEAUT32.197) 4259 * 4260 * Convert a VT_BSTR to a DECIMAL. 4261 * 4262 * PARAMS 4263 * strIn [I] Source 4264 * lcid [I] LCID for the conversion 4265 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 4266 * pDecOut [O] Destination 4267 * 4268 * RETURNS 4269 * Success: S_OK. 4270 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 4271 */ 4272 HRESULT WINAPI VarDecFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DECIMAL* pDecOut) 4273 { 4274 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDecOut, VT_DECIMAL); 4275 } 4276 4277 /************************************************************************ 4278 * VarDecFromDisp (OLEAUT32.198) 4279 * 4280 * Convert a VT_DISPATCH to a DECIMAL. 4281 * 4282 * PARAMS 4283 * pdispIn [I] Source 4284 * lcid [I] LCID for conversion 4285 * pDecOut [O] Destination 4286 * 4287 * RETURNS 4288 * Success: S_OK. 4289 * Failure: DISP_E_TYPEMISMATCH, if the type cannot be converted 4290 */ 4291 HRESULT WINAPI VarDecFromDisp(IDispatch* pdispIn, LCID lcid, DECIMAL* pDecOut) 4292 { 4293 return VARIANT_FromDisp(pdispIn, lcid, pDecOut, VT_DECIMAL, 0); 4294 } 4295 4296 /************************************************************************ 4297 * VarDecFromBool (OLEAUT32.199) 4298 * 4299 * Convert a VT_BOOL to a DECIMAL. 4300 * 4301 * PARAMS 4302 * bIn [I] Source 4303 * pDecOut [O] Destination 4304 * 4305 * RETURNS 4306 * S_OK. 4307 * 4308 * NOTES 4309 * The value is converted to either 0 (if bIn is FALSE) or -1 (TRUE). 4310 */ 4311 HRESULT WINAPI VarDecFromBool(VARIANT_BOOL bIn, DECIMAL* pDecOut) 4312 { 4313 DEC_HI32(pDecOut) = 0; 4314 DEC_MID32(pDecOut) = 0; 4315 if (bIn) 4316 { 4317 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0); 4318 DEC_LO32(pDecOut) = 1; 4319 } 4320 else 4321 { 4322 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0); 4323 DEC_LO32(pDecOut) = 0; 4324 } 4325 return S_OK; 4326 } 4327 4328 /************************************************************************ 4329 * VarDecFromI1 (OLEAUT32.241) 4330 * 4331 * Convert a VT_I1 to a DECIMAL. 4332 * 4333 * PARAMS 4334 * cIn [I] Source 4335 * pDecOut [O] Destination 4336 * 4337 * RETURNS 4338 * S_OK. 4339 */ 4340 HRESULT WINAPI VarDecFromI1(signed char cIn, DECIMAL* pDecOut) 4341 { 4342 return VarDecFromI4(cIn, pDecOut); 4343 } 4344 4345 /************************************************************************ 4346 * VarDecFromUI2 (OLEAUT32.242) 4347 * 4348 * Convert a VT_UI2 to a DECIMAL. 4349 * 4350 * PARAMS 4351 * usIn [I] Source 4352 * pDecOut [O] Destination 4353 * 4354 * RETURNS 4355 * S_OK. 4356 */ 4357 HRESULT WINAPI VarDecFromUI2(USHORT usIn, DECIMAL* pDecOut) 4358 { 4359 return VarDecFromUI4(usIn, pDecOut); 4360 } 4361 4362 /************************************************************************ 4363 * VarDecFromUI4 (OLEAUT32.243) 4364 * 4365 * Convert a VT_UI4 to a DECIMAL. 4366 * 4367 * PARAMS 4368 * ulIn [I] Source 4369 * pDecOut [O] Destination 4370 * 4371 * RETURNS 4372 * S_OK. 4373 */ 4374 HRESULT WINAPI VarDecFromUI4(ULONG ulIn, DECIMAL* pDecOut) 4375 { 4376 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0); 4377 DEC_HI32(pDecOut) = 0; 4378 DEC_MID32(pDecOut) = 0; 4379 DEC_LO32(pDecOut) = ulIn; 4380 return S_OK; 4381 } 4382 4383 /************************************************************************ 4384 * VarDecFromI8 (OLEAUT32.374) 4385 * 4386 * Convert a VT_I8 to a DECIMAL. 4387 * 4388 * PARAMS 4389 * llIn [I] Source 4390 * pDecOut [O] Destination 4391 * 4392 * RETURNS 4393 * S_OK. 4394 */ 4395 HRESULT WINAPI VarDecFromI8(LONG64 llIn, DECIMAL* pDecOut) 4396 { 4397 PULARGE_INTEGER pLi = (PULARGE_INTEGER)&llIn; 4398 4399 DEC_HI32(pDecOut) = 0; 4400 4401 /* Note: This assumes 2s complement integer representation */ 4402 if (pLi->u.HighPart & 0x80000000) 4403 { 4404 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0); 4405 DEC_LO64(pDecOut) = -pLi->QuadPart; 4406 } 4407 else 4408 { 4409 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0); 4410 DEC_MID32(pDecOut) = pLi->u.HighPart; 4411 DEC_LO32(pDecOut) = pLi->u.LowPart; 4412 } 4413 return S_OK; 4414 } 4415 4416 /************************************************************************ 4417 * VarDecFromUI8 (OLEAUT32.375) 4418 * 4419 * Convert a VT_UI8 to a DECIMAL. 4420 * 4421 * PARAMS 4422 * ullIn [I] Source 4423 * pDecOut [O] Destination 4424 * 4425 * RETURNS 4426 * S_OK. 4427 */ 4428 HRESULT WINAPI VarDecFromUI8(ULONG64 ullIn, DECIMAL* pDecOut) 4429 { 4430 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0); 4431 DEC_HI32(pDecOut) = 0; 4432 DEC_LO64(pDecOut) = ullIn; 4433 return S_OK; 4434 } 4435 4436 /* Make two DECIMALS the same scale; used by math functions below */ 4437 static HRESULT VARIANT_DecScale(const DECIMAL** ppDecLeft, 4438 const DECIMAL** ppDecRight, 4439 DECIMAL pDecOut[2]) 4440 { 4441 static DECIMAL scaleFactor; 4442 unsigned char remainder; 4443 DECIMAL decTemp; 4444 VARIANT_DI di; 4445 int scaleAmount, i; 4446 4447 if (DEC_SIGN(*ppDecLeft) & ~DECIMAL_NEG || DEC_SIGN(*ppDecRight) & ~DECIMAL_NEG) 4448 return E_INVALIDARG; 4449 4450 DEC_LO32(&scaleFactor) = 10; 4451 4452 i = scaleAmount = DEC_SCALE(*ppDecLeft) - DEC_SCALE(*ppDecRight); 4453 4454 if (!scaleAmount) 4455 return S_OK; /* Same scale */ 4456 4457 if (scaleAmount > 0) 4458 { 4459 decTemp = *(*ppDecRight); /* Left is bigger - scale the right hand side */ 4460 *ppDecRight = &pDecOut[0]; 4461 } 4462 else 4463 { 4464 decTemp = *(*ppDecLeft); /* Right is bigger - scale the left hand side */ 4465 *ppDecLeft = &pDecOut[0]; 4466 i = -scaleAmount; 4467 } 4468 4469 /* Multiply up the value to be scaled by the correct amount (if possible) */ 4470 while (i > 0 && SUCCEEDED(VarDecMul(&decTemp, &scaleFactor, &pDecOut[0]))) 4471 { 4472 decTemp = pDecOut[0]; 4473 i--; 4474 } 4475 4476 if (!i) 4477 { 4478 DEC_SCALE(&pDecOut[0]) += (scaleAmount > 0) ? scaleAmount : (-scaleAmount); 4479 return S_OK; /* Same scale */ 4480 } 4481 4482 /* Scaling further not possible, reduce accuracy of other argument */ 4483 pDecOut[0] = decTemp; 4484 if (scaleAmount > 0) 4485 { 4486 DEC_SCALE(&pDecOut[0]) += scaleAmount - i; 4487 VARIANT_DIFromDec(*ppDecLeft, &di); 4488 *ppDecLeft = &pDecOut[1]; 4489 } 4490 else 4491 { 4492 DEC_SCALE(&pDecOut[0]) += (-scaleAmount) - i; 4493 VARIANT_DIFromDec(*ppDecRight, &di); 4494 *ppDecRight = &pDecOut[1]; 4495 } 4496 4497 di.scale -= i; 4498 remainder = 0; 4499 while (i-- > 0 && !VARIANT_int_iszero(di.bitsnum, sizeof(di.bitsnum)/sizeof(DWORD))) 4500 { 4501 remainder = VARIANT_int_divbychar(di.bitsnum, sizeof(di.bitsnum)/sizeof(DWORD), 10); 4502 if (remainder > 0) WARN("losing significant digits (remainder %u)...\n", remainder); 4503 } 4504 4505 /* round up the result - native oleaut32 does this */ 4506 if (remainder >= 5) { 4507 for (remainder = 1, i = 0; i < sizeof(di.bitsnum)/sizeof(DWORD) && remainder; i++) { 4508 ULONGLONG digit = di.bitsnum[i] + 1; 4509 remainder = (digit > 0xFFFFFFFF) ? 1 : 0; 4510 di.bitsnum[i] = digit & 0xFFFFFFFF; 4511 } 4512 } 4513 4514 VARIANT_DecFromDI(&di, &pDecOut[1]); 4515 return S_OK; 4516 } 4517 4518 /* Add two unsigned 32 bit values with overflow */ 4519 static ULONG VARIANT_Add(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh) 4520 { 4521 ULARGE_INTEGER ul64; 4522 4523 ul64.QuadPart = (ULONG64)ulLeft + (ULONG64)ulRight + (ULONG64)*pulHigh; 4524 *pulHigh = ul64.u.HighPart; 4525 return ul64.u.LowPart; 4526 } 4527 4528 /* Subtract two unsigned 32 bit values with underflow */ 4529 static ULONG VARIANT_Sub(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh) 4530 { 4531 BOOL invert = FALSE; 4532 ULARGE_INTEGER ul64; 4533 4534 ul64.QuadPart = (LONG64)ulLeft - (ULONG64)ulRight; 4535 if (ulLeft < ulRight) 4536 invert = TRUE; 4537 4538 if (ul64.QuadPart > (ULONG64)*pulHigh) 4539 ul64.QuadPart -= (ULONG64)*pulHigh; 4540 else 4541 { 4542 ul64.QuadPart -= (ULONG64)*pulHigh; 4543 invert = TRUE; 4544 } 4545 if (invert) 4546 ul64.u.HighPart = -ul64.u.HighPart ; 4547 4548 *pulHigh = ul64.u.HighPart; 4549 return ul64.u.LowPart; 4550 } 4551 4552 /* Multiply two unsigned 32 bit values with overflow */ 4553 static ULONG VARIANT_Mul(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh) 4554 { 4555 ULARGE_INTEGER ul64; 4556 4557 ul64.QuadPart = (ULONG64)ulLeft * (ULONG64)ulRight + (ULONG64)*pulHigh; 4558 *pulHigh = ul64.u.HighPart; 4559 return ul64.u.LowPart; 4560 } 4561 4562 /* Compare two decimals that have the same scale */ 4563 static inline int VARIANT_DecCmp(const DECIMAL *pDecLeft, const DECIMAL *pDecRight) 4564 { 4565 if ( DEC_HI32(pDecLeft) < DEC_HI32(pDecRight) || 4566 (DEC_HI32(pDecLeft) <= DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) < DEC_LO64(pDecRight))) 4567 return -1; 4568 else if (DEC_HI32(pDecLeft) == DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) == DEC_LO64(pDecRight)) 4569 return 0; 4570 return 1; 4571 } 4572 4573 /************************************************************************ 4574 * VarDecAdd (OLEAUT32.177) 4575 * 4576 * Add one DECIMAL to another. 4577 * 4578 * PARAMS 4579 * pDecLeft [I] Source 4580 * pDecRight [I] Value to add 4581 * pDecOut [O] Destination 4582 * 4583 * RETURNS 4584 * Success: S_OK. 4585 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 4586 */ 4587 HRESULT WINAPI VarDecAdd(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut) 4588 { 4589 HRESULT hRet; 4590 DECIMAL scaled[2]; 4591 4592 hRet = VARIANT_DecScale(&pDecLeft, &pDecRight, scaled); 4593 4594 if (SUCCEEDED(hRet)) 4595 { 4596 /* Our decimals now have the same scale, we can add them as 96 bit integers */ 4597 ULONG overflow = 0; 4598 BYTE sign = DECIMAL_POS; 4599 int cmp; 4600 4601 /* Correct for the sign of the result */ 4602 if (DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight)) 4603 { 4604 /* -x + -y : Negative */ 4605 sign = DECIMAL_NEG; 4606 goto VarDecAdd_AsPositive; 4607 } 4608 else if (DEC_SIGN(pDecLeft) && !DEC_SIGN(pDecRight)) 4609 { 4610 cmp = VARIANT_DecCmp(pDecLeft, pDecRight); 4611 4612 /* -x + y : Negative if x > y */ 4613 if (cmp > 0) 4614 { 4615 sign = DECIMAL_NEG; 4616 VarDecAdd_AsNegative: 4617 DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow); 4618 DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow); 4619 DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow); 4620 } 4621 else 4622 { 4623 VarDecAdd_AsInvertedNegative: 4624 DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecRight), DEC_LO32(pDecLeft), &overflow); 4625 DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecRight), DEC_MID32(pDecLeft), &overflow); 4626 DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecRight), DEC_HI32(pDecLeft), &overflow); 4627 } 4628 } 4629 else if (!DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight)) 4630 { 4631 cmp = VARIANT_DecCmp(pDecLeft, pDecRight); 4632 4633 /* x + -y : Negative if x <= y */ 4634 if (cmp <= 0) 4635 { 4636 sign = DECIMAL_NEG; 4637 goto VarDecAdd_AsInvertedNegative; 4638 } 4639 goto VarDecAdd_AsNegative; 4640 } 4641 else 4642 { 4643 /* x + y : Positive */ 4644 VarDecAdd_AsPositive: 4645 DEC_LO32(pDecOut) = VARIANT_Add(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow); 4646 DEC_MID32(pDecOut) = VARIANT_Add(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow); 4647 DEC_HI32(pDecOut) = VARIANT_Add(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow); 4648 } 4649 4650 if (overflow) 4651 return DISP_E_OVERFLOW; /* overflowed */ 4652 4653 DEC_SCALE(pDecOut) = DEC_SCALE(pDecLeft); 4654 DEC_SIGN(pDecOut) = sign; 4655 } 4656 return hRet; 4657 } 4658 4659 /* translate from external DECIMAL format into an internal representation */ 4660 static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to) 4661 { 4662 to->scale = DEC_SCALE(from); 4663 to->sign = DEC_SIGN(from) ? 1 : 0; 4664 4665 to->bitsnum[0] = DEC_LO32(from); 4666 to->bitsnum[1] = DEC_MID32(from); 4667 to->bitsnum[2] = DEC_HI32(from); 4668 } 4669 4670 static void VARIANT_DecFromDI(const VARIANT_DI * from, DECIMAL * to) 4671 { 4672 if (from->sign) { 4673 DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_NEG, from->scale); 4674 } else { 4675 DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_POS, from->scale); 4676 } 4677 4678 DEC_LO32(to) = from->bitsnum[0]; 4679 DEC_MID32(to) = from->bitsnum[1]; 4680 DEC_HI32(to) = from->bitsnum[2]; 4681 } 4682 4683 /* clear an internal representation of a DECIMAL */ 4684 static void VARIANT_DI_clear(VARIANT_DI * i) 4685 { 4686 memset(i, 0, sizeof(VARIANT_DI)); 4687 } 4688 4689 /* divide the (unsigned) number stored in p (LSB) by a byte value (<= 0xff). Any nonzero 4690 size is supported. The value in p is replaced by the quotient of the division, and 4691 the remainder is returned as a result. This routine is most often used with a divisor 4692 of 10 in order to scale up numbers, and in the DECIMAL->string conversion. 4693 */ 4694 static unsigned char VARIANT_int_divbychar(DWORD * p, unsigned int n, unsigned char divisor) 4695 { 4696 if (divisor == 0) { 4697 /* division by 0 */ 4698 return 0xFF; 4699 } else if (divisor == 1) { 4700 /* dividend remains unchanged */ 4701 return 0; 4702 } else { 4703 unsigned char remainder = 0; 4704 ULONGLONG iTempDividend; 4705 signed int i; 4706 4707 for (i = n - 1; i >= 0 && !p[i]; i--); /* skip leading zeros */ 4708 for (; i >= 0; i--) { 4709 iTempDividend = ((ULONGLONG)remainder << 32) + p[i]; 4710 remainder = iTempDividend % divisor; 4711 p[i] = iTempDividend / divisor; 4712 } 4713 4714 return remainder; 4715 } 4716 } 4717 4718 /* check to test if encoded number is a zero. Returns 1 if zero, 0 for nonzero */ 4719 static BOOL VARIANT_int_iszero(const DWORD * p, unsigned int n) 4720 { 4721 for (; n > 0; n--) if (*p++ != 0) return FALSE; 4722 return TRUE; 4723 } 4724 4725 /* multiply two DECIMALS, without changing either one, and place result in third 4726 parameter. Result is normalized when scale is > 0. Attempts to remove significant 4727 digits when scale > 0 in order to fit an overflowing result. Final overflow 4728 flag is returned. 4729 */ 4730 static int VARIANT_DI_mul(const VARIANT_DI * a, const VARIANT_DI * b, VARIANT_DI * result) 4731 { 4732 BOOL r_overflow = FALSE; 4733 DWORD running[6]; 4734 signed int mulstart; 4735 4736 VARIANT_DI_clear(result); 4737 result->sign = (a->sign ^ b->sign) ? 1 : 0; 4738 4739 /* Multiply 128-bit operands into a (max) 256-bit result. The scale 4740 of the result is formed by adding the scales of the operands. 4741 */ 4742 result->scale = a->scale + b->scale; 4743 memset(running, 0, sizeof(running)); 4744 4745 /* count number of leading zero-bytes in operand A */ 4746 for (mulstart = sizeof(a->bitsnum)/sizeof(DWORD) - 1; mulstart >= 0 && !a->bitsnum[mulstart]; mulstart--); 4747 if (mulstart < 0) { 4748 /* result is 0, because operand A is 0 */ 4749 result->scale = 0; 4750 result->sign = 0; 4751 } else { 4752 unsigned char remainder = 0; 4753 int iA; 4754 4755 /* perform actual multiplication */ 4756 for (iA = 0; iA <= mulstart; iA++) { 4757 ULONG iOverflowMul; 4758 int iB; 4759 4760 for (iOverflowMul = 0, iB = 0; iB < sizeof(b->bitsnum)/sizeof(DWORD); iB++) { 4761 ULONG iRV; 4762 int iR; 4763 4764 iRV = VARIANT_Mul(b->bitsnum[iB], a->bitsnum[iA], &iOverflowMul); 4765 iR = iA + iB; 4766 do { 4767 running[iR] = VARIANT_Add(running[iR], 0, &iRV); 4768 iR++; 4769 } while (iRV); 4770 } 4771 } 4772 4773 /* Too bad - native oleaut does not do this, so we should not either */ 4774 #if 0 4775 /* While the result is divisible by 10, and the scale > 0, divide by 10. 4776 This operation should not lose significant digits, and gives an 4777 opportunity to reduce the possibility of overflows in future 4778 operations issued by the application. 4779 */ 4780 while (result->scale > 0) { 4781 memcpy(quotient, running, sizeof(quotient)); 4782 remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10); 4783 if (remainder > 0) break; 4784 memcpy(running, quotient, sizeof(quotient)); 4785 result->scale--; 4786 } 4787 #endif 4788 /* While the 256-bit result overflows, and the scale > 0, divide by 10. 4789 This operation *will* lose significant digits of the result because 4790 all the factors of 10 were consumed by the previous operation. 4791 */ 4792 while (result->scale > 0 && !VARIANT_int_iszero( 4793 running + sizeof(result->bitsnum) / sizeof(DWORD), 4794 (sizeof(running) - sizeof(result->bitsnum)) / sizeof(DWORD))) { 4795 4796 remainder = VARIANT_int_divbychar(running, sizeof(running) / sizeof(DWORD), 10); 4797 if (remainder > 0) WARN("losing significant digits (remainder %u)...\n", remainder); 4798 result->scale--; 4799 } 4800 4801 /* round up the result - native oleaut32 does this */ 4802 if (remainder >= 5) { 4803 unsigned int i; 4804 for (remainder = 1, i = 0; i < sizeof(running)/sizeof(DWORD) && remainder; i++) { 4805 ULONGLONG digit = running[i] + 1; 4806 remainder = (digit > 0xFFFFFFFF) ? 1 : 0; 4807 running[i] = digit & 0xFFFFFFFF; 4808 } 4809 } 4810 4811 /* Signal overflow if scale == 0 and 256-bit result still overflows, 4812 and copy result bits into result structure 4813 */ 4814 r_overflow = !VARIANT_int_iszero( 4815 running + sizeof(result->bitsnum)/sizeof(DWORD), 4816 (sizeof(running) - sizeof(result->bitsnum))/sizeof(DWORD)); 4817 memcpy(result->bitsnum, running, sizeof(result->bitsnum)); 4818 } 4819 return r_overflow; 4820 } 4821 4822 /* cast DECIMAL into string. Any scale should be handled properly. en_US locale is 4823 hardcoded (period for decimal separator, dash as negative sign). Returns TRUE for 4824 success, FALSE if insufficient space in output buffer. 4825 */ 4826 static BOOL VARIANT_DI_tostringW(const VARIANT_DI * a, WCHAR * s, unsigned int n) 4827 { 4828 BOOL overflow = FALSE; 4829 DWORD quotient[3]; 4830 unsigned char remainder; 4831 unsigned int i; 4832 4833 /* place negative sign */ 4834 if (!VARIANT_int_iszero(a->bitsnum, sizeof(a->bitsnum) / sizeof(DWORD)) && a->sign) { 4835 if (n > 0) { 4836 *s++ = '-'; 4837 n--; 4838 } 4839 else overflow = TRUE; 4840 } 4841 4842 /* prepare initial 0 */ 4843 if (!overflow) { 4844 if (n >= 2) { 4845 s[0] = '0'; 4846 s[1] = '\0'; 4847 } else overflow = TRUE; 4848 } 4849 4850 i = 0; 4851 memcpy(quotient, a->bitsnum, sizeof(a->bitsnum)); 4852 while (!overflow && !VARIANT_int_iszero(quotient, sizeof(quotient) / sizeof(DWORD))) { 4853 remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10); 4854 if (i + 2 > n) { 4855 overflow = TRUE; 4856 } else { 4857 s[i++] = '0' + remainder; 4858 s[i] = '\0'; 4859 } 4860 } 4861 4862 if (!overflow && !VARIANT_int_iszero(a->bitsnum, sizeof(a->bitsnum) / sizeof(DWORD))) { 4863 4864 /* reverse order of digits */ 4865 WCHAR * x = s; WCHAR * y = s + i - 1; 4866 while (x < y) { 4867 *x ^= *y; 4868 *y ^= *x; 4869 *x++ ^= *y--; 4870 } 4871 4872 /* check for decimal point. "i" now has string length */ 4873 if (i <= a->scale) { 4874 unsigned int numzeroes = a->scale + 1 - i; 4875 if (i + 1 + numzeroes >= n) { 4876 overflow = TRUE; 4877 } else { 4878 memmove(s + numzeroes, s, (i + 1) * sizeof(WCHAR)); 4879 i += numzeroes; 4880 while (numzeroes > 0) { 4881 s[--numzeroes] = '0'; 4882 } 4883 } 4884 } 4885 4886 /* place decimal point */ 4887 if (a->scale > 0) { 4888 unsigned int periodpos = i - a->scale; 4889 if (i + 2 >= n) { 4890 overflow = TRUE; 4891 } else { 4892 memmove(s + periodpos + 1, s + periodpos, (i + 1 - periodpos) * sizeof(WCHAR)); 4893 s[periodpos] = '.'; i++; 4894 4895 /* remove extra zeros at the end, if any */ 4896 while (s[i - 1] == '0') s[--i] = '\0'; 4897 if (s[i - 1] == '.') s[--i] = '\0'; 4898 } 4899 } 4900 } 4901 4902 return !overflow; 4903 } 4904 4905 /* shift the bits of a DWORD array to the left. p[0] is assumed LSB */ 4906 static void VARIANT_int_shiftleft(DWORD * p, unsigned int n, unsigned int shift) 4907 { 4908 DWORD shifted; 4909 unsigned int i; 4910 4911 /* shift whole DWORDs to the left */ 4912 while (shift >= 32) 4913 { 4914 memmove(p + 1, p, (n - 1) * sizeof(DWORD)); 4915 *p = 0; shift -= 32; 4916 } 4917 4918 /* shift remainder (1..31 bits) */ 4919 shifted = 0; 4920 if (shift > 0) for (i = 0; i < n; i++) 4921 { 4922 DWORD b; 4923 b = p[i] >> (32 - shift); 4924 p[i] = (p[i] << shift) | shifted; 4925 shifted = b; 4926 } 4927 } 4928 4929 /* add the (unsigned) numbers stored in two DWORD arrays with LSB at index 0. 4930 Value at v is incremented by the value at p. Any size is supported, provided 4931 that v is not shorter than p. Any unapplied carry is returned as a result. 4932 */ 4933 static unsigned char VARIANT_int_add(DWORD * v, unsigned int nv, const DWORD * p, 4934 unsigned int np) 4935 { 4936 unsigned char carry = 0; 4937 4938 if (nv >= np) { 4939 ULONGLONG sum; 4940 unsigned int i; 4941 4942 for (i = 0; i < np; i++) { 4943 sum = (ULONGLONG)v[i] 4944 + (ULONGLONG)p[i] 4945 + (ULONGLONG)carry; 4946 v[i] = sum & 0xffffffff; 4947 carry = sum >> 32; 4948 } 4949 for (; i < nv && carry; i++) { 4950 sum = (ULONGLONG)v[i] 4951 + (ULONGLONG)carry; 4952 v[i] = sum & 0xffffffff; 4953 carry = sum >> 32; 4954 } 4955 } 4956 return carry; 4957 } 4958 4959 /* perform integral division with operand p as dividend. Parameter n indicates 4960 number of available DWORDs in divisor p, but available space in p must be 4961 actually at least 2 * n DWORDs, because the remainder of the integral 4962 division is built in the next n DWORDs past the start of the quotient. This 4963 routine replaces the dividend in p with the quotient, and appends n 4964 additional DWORDs for the remainder. 4965 4966 Thanks to Lee & Mark Atkinson for their book _Using_C_ (my very first book on 4967 C/C++ :-) where the "longhand binary division" algorithm was exposed for the 4968 source code to the VLI (Very Large Integer) division operator. This algorithm 4969 was then heavily modified by me (Alex Villacis Lasso) in order to handle 4970 variably-scaled integers such as the MS DECIMAL representation. 4971 */ 4972 static void VARIANT_int_div(DWORD * p, unsigned int n, const DWORD * divisor, 4973 unsigned int dn) 4974 { 4975 unsigned int i; 4976 DWORD tempsub[8]; 4977 DWORD * negdivisor = tempsub + n; 4978 4979 /* build 2s-complement of divisor */ 4980 for (i = 0; i < n; i++) negdivisor[i] = (i < dn) ? ~divisor[i] : 0xFFFFFFFF; 4981 p[n] = 1; 4982 VARIANT_int_add(negdivisor, n, p + n, 1); 4983 memset(p + n, 0, n * sizeof(DWORD)); 4984 4985 /* skip all leading zero DWORDs in quotient */ 4986 for (i = 0; i < n && !p[n - 1]; i++) VARIANT_int_shiftleft(p, n, 32); 4987 /* i is now number of DWORDs left to process */ 4988 for (i <<= 5; i < (n << 5); i++) { 4989 VARIANT_int_shiftleft(p, n << 1, 1); /* shl quotient+remainder */ 4990 4991 /* trial subtraction */ 4992 memcpy(tempsub, p + n, n * sizeof(DWORD)); 4993 VARIANT_int_add(tempsub, n, negdivisor, n); 4994 4995 /* check whether result of subtraction was negative */ 4996 if ((tempsub[n - 1] & 0x80000000) == 0) { 4997 memcpy(p + n, tempsub, n * sizeof(DWORD)); 4998 p[0] |= 1; 4999 } 5000 } 5001 } 5002 5003 /* perform integral multiplication by a byte operand. Used for scaling by 10 */ 5004 static unsigned char VARIANT_int_mulbychar(DWORD * p, unsigned int n, unsigned char m) 5005 { 5006 unsigned int i; 5007 ULONG iOverflowMul; 5008 5009 for (iOverflowMul = 0, i = 0; i < n; i++) 5010 p[i] = VARIANT_Mul(p[i], m, &iOverflowMul); 5011 return (unsigned char)iOverflowMul; 5012 } 5013 5014 /* increment value in A by the value indicated in B, with scale adjusting. 5015 Modifies parameters by adjusting scales. Returns 0 if addition was 5016 successful, nonzero if a parameter underflowed before it could be 5017 successfully used in the addition. 5018 */ 5019 static int VARIANT_int_addlossy( 5020 DWORD * a, int * ascale, unsigned int an, 5021 DWORD * b, int * bscale, unsigned int bn) 5022 { 5023 int underflow = 0; 5024 5025 if (VARIANT_int_iszero(a, an)) { 5026 /* if A is zero, copy B into A, after removing digits */ 5027 while (bn > an && !VARIANT_int_iszero(b + an, bn - an)) { 5028 VARIANT_int_divbychar(b, bn, 10); 5029 (*bscale)--; 5030 } 5031 memcpy(a, b, an * sizeof(DWORD)); 5032 *ascale = *bscale; 5033 } else if (!VARIANT_int_iszero(b, bn)) { 5034 unsigned int tn = an + 1; 5035 DWORD t[5]; 5036 5037 if (bn + 1 > tn) tn = bn + 1; 5038 if (*ascale != *bscale) { 5039 /* first (optimistic) try - try to scale down the one with the bigger 5040 scale, while this number is divisible by 10 */ 5041 DWORD * digitchosen; 5042 unsigned int nchosen; 5043 int * scalechosen; 5044 int targetscale; 5045 5046 if (*ascale < *bscale) { 5047 targetscale = *ascale; 5048 scalechosen = bscale; 5049 digitchosen = b; 5050 nchosen = bn; 5051 } else { 5052 targetscale = *bscale; 5053 scalechosen = ascale; 5054 digitchosen = a; 5055 nchosen = an; 5056 } 5057 memset(t, 0, tn * sizeof(DWORD)); 5058 memcpy(t, digitchosen, nchosen * sizeof(DWORD)); 5059 5060 /* divide by 10 until target scale is reached */ 5061 while (*scalechosen > targetscale) { 5062 unsigned char remainder = VARIANT_int_divbychar(t, tn, 10); 5063 if (!remainder) { 5064 (*scalechosen)--; 5065 memcpy(digitchosen, t, nchosen * sizeof(DWORD)); 5066 } else break; 5067 } 5068 } 5069 5070 if (*ascale != *bscale) { 5071 DWORD * digitchosen; 5072 unsigned int nchosen; 5073 int * scalechosen; 5074 int targetscale; 5075 5076 /* try to scale up the one with the smaller scale */ 5077 if (*ascale > *bscale) { 5078 targetscale = *ascale; 5079 scalechosen = bscale; 5080 digitchosen = b; 5081 nchosen = bn; 5082 } else { 5083 targetscale = *bscale; 5084 scalechosen = ascale; 5085 digitchosen = a; 5086 nchosen = an; 5087 } 5088 memset(t, 0, tn * sizeof(DWORD)); 5089 memcpy(t, digitchosen, nchosen * sizeof(DWORD)); 5090 5091 /* multiply by 10 until target scale is reached, or 5092 significant bytes overflow the number 5093 */ 5094 while (*scalechosen < targetscale && t[nchosen] == 0) { 5095 VARIANT_int_mulbychar(t, tn, 10); 5096 if (t[nchosen] == 0) { 5097 /* still does not overflow */ 5098 (*scalechosen)++; 5099 memcpy(digitchosen, t, nchosen * sizeof(DWORD)); 5100 } 5101 } 5102 } 5103 5104 if (*ascale != *bscale) { 5105 /* still different? try to scale down the one with the bigger scale 5106 (this *will* lose significant digits) */ 5107 DWORD * digitchosen; 5108 unsigned int nchosen; 5109 int * scalechosen; 5110 int targetscale; 5111 5112 if (*ascale < *bscale) { 5113 targetscale = *ascale; 5114 scalechosen = bscale; 5115 digitchosen = b; 5116 nchosen = bn; 5117 } else { 5118 targetscale = *bscale; 5119 scalechosen = ascale; 5120 digitchosen = a; 5121 nchosen = an; 5122 } 5123 memset(t, 0, tn * sizeof(DWORD)); 5124 memcpy(t, digitchosen, nchosen * sizeof(DWORD)); 5125 5126 /* divide by 10 until target scale is reached */ 5127 while (*scalechosen > targetscale) { 5128 VARIANT_int_divbychar(t, tn, 10); 5129 (*scalechosen)--; 5130 memcpy(digitchosen, t, nchosen * sizeof(DWORD)); 5131 } 5132 } 5133 5134 /* check whether any of the operands still has significant digits 5135 (underflow case 1) 5136 */ 5137 if (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn)) { 5138 underflow = 1; 5139 } else { 5140 /* at this step, both numbers have the same scale and can be added 5141 as integers. However, the result might not fit in A, so further 5142 scaling down might be necessary. 5143 */ 5144 while (!underflow) { 5145 memset(t, 0, tn * sizeof(DWORD)); 5146 memcpy(t, a, an * sizeof(DWORD)); 5147 5148 VARIANT_int_add(t, tn, b, bn); 5149 if (VARIANT_int_iszero(t + an, tn - an)) { 5150 /* addition was successful */ 5151 memcpy(a, t, an * sizeof(DWORD)); 5152 break; 5153 } else { 5154 /* addition overflowed - remove significant digits 5155 from both operands and try again */ 5156 VARIANT_int_divbychar(a, an, 10); (*ascale)--; 5157 VARIANT_int_divbychar(b, bn, 10); (*bscale)--; 5158 /* check whether any operand keeps significant digits after 5159 scaledown (underflow case 2) 5160 */ 5161 underflow = (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn)); 5162 } 5163 } 5164 } 5165 } 5166 return underflow; 5167 } 5168 5169 /* perform complete DECIMAL division in the internal representation. Returns 5170 0 if the division was completed (even if quotient is set to 0), or nonzero 5171 in case of quotient overflow. 5172 */ 5173 static HRESULT VARIANT_DI_div(const VARIANT_DI * dividend, const VARIANT_DI * divisor, 5174 VARIANT_DI * quotient, BOOL round_remainder) 5175 { 5176 HRESULT r_overflow = S_OK; 5177 5178 if (VARIANT_int_iszero(divisor->bitsnum, sizeof(divisor->bitsnum)/sizeof(DWORD))) { 5179 /* division by 0 */ 5180 r_overflow = DISP_E_DIVBYZERO; 5181 } else if (VARIANT_int_iszero(dividend->bitsnum, sizeof(dividend->bitsnum)/sizeof(DWORD))) { 5182 VARIANT_DI_clear(quotient); 5183 } else { 5184 int quotientscale, remainderscale, tempquotientscale; 5185 DWORD remainderplusquotient[8]; 5186 int underflow; 5187 5188 quotientscale = remainderscale = (int)dividend->scale - (int)divisor->scale; 5189 tempquotientscale = quotientscale; 5190 VARIANT_DI_clear(quotient); 5191 quotient->sign = (dividend->sign ^ divisor->sign) ? 1 : 0; 5192 5193 /* The following strategy is used for division 5194 1) if there was a nonzero remainder from previous iteration, use it as 5195 dividend for this iteration, else (for first iteration) use intended 5196 dividend 5197 2) perform integer division in temporary buffer, develop quotient in 5198 low-order part, remainder in high-order part 5199 3) add quotient from step 2 to final result, with possible loss of 5200 significant digits 5201 4) multiply integer part of remainder by 10, while incrementing the 5202 scale of the remainder. This operation preserves the intended value 5203 of the remainder. 5204 5) loop to step 1 until one of the following is true: 5205 a) remainder is zero (exact division achieved) 5206 b) addition in step 3 fails to modify bits in quotient (remainder underflow) 5207 */ 5208 memset(remainderplusquotient, 0, sizeof(remainderplusquotient)); 5209 memcpy(remainderplusquotient, dividend->bitsnum, sizeof(dividend->bitsnum)); 5210 do { 5211 VARIANT_int_div( 5212 remainderplusquotient, 4, 5213 divisor->bitsnum, sizeof(divisor->bitsnum)/sizeof(DWORD)); 5214 underflow = VARIANT_int_addlossy( 5215 quotient->bitsnum, "ientscale, sizeof(quotient->bitsnum) / sizeof(DWORD), 5216 remainderplusquotient, &tempquotientscale, 4); 5217 if (round_remainder) { 5218 if(remainderplusquotient[4] >= 5){ 5219 unsigned int i; 5220 unsigned char remainder = 1; 5221 for (i = 0; i < sizeof(quotient->bitsnum) / sizeof(DWORD) && remainder; i++) { 5222 ULONGLONG digit = quotient->bitsnum[i] + 1; 5223 remainder = (digit > 0xFFFFFFFF) ? 1 : 0; 5224 quotient->bitsnum[i] = digit & 0xFFFFFFFF; 5225 } 5226 } 5227 memset(remainderplusquotient, 0, sizeof(remainderplusquotient)); 5228 } else { 5229 VARIANT_int_mulbychar(remainderplusquotient + 4, 4, 10); 5230 memcpy(remainderplusquotient, remainderplusquotient + 4, 4 * sizeof(DWORD)); 5231 } 5232 tempquotientscale = ++remainderscale; 5233 } while (!underflow && !VARIANT_int_iszero(remainderplusquotient + 4, 4)); 5234 5235 /* quotient scale might now be negative (extremely big number). If, so, try 5236 to multiply quotient by 10 (without overflowing), while adjusting the scale, 5237 until scale is 0. If this cannot be done, it is a real overflow. 5238 */ 5239 while (r_overflow == S_OK && quotientscale < 0) { 5240 memset(remainderplusquotient, 0, sizeof(remainderplusquotient)); 5241 memcpy(remainderplusquotient, quotient->bitsnum, sizeof(quotient->bitsnum)); 5242 VARIANT_int_mulbychar(remainderplusquotient, sizeof(remainderplusquotient)/sizeof(DWORD), 10); 5243 if (VARIANT_int_iszero(remainderplusquotient + sizeof(quotient->bitsnum)/sizeof(DWORD), 5244 (sizeof(remainderplusquotient) - sizeof(quotient->bitsnum))/sizeof(DWORD))) { 5245 quotientscale++; 5246 memcpy(quotient->bitsnum, remainderplusquotient, sizeof(quotient->bitsnum)); 5247 } else r_overflow = DISP_E_OVERFLOW; 5248 } 5249 if (r_overflow == S_OK) { 5250 if (quotientscale <= 255) quotient->scale = quotientscale; 5251 else VARIANT_DI_clear(quotient); 5252 } 5253 } 5254 return r_overflow; 5255 } 5256 5257 /* This procedure receives a VARIANT_DI with a defined mantissa and sign, but 5258 with an undefined scale, which will be assigned to (if possible). It also 5259 receives an exponent of 2. This procedure will then manipulate the mantissa 5260 and calculate a corresponding scale, so that the exponent2 value is assimilated 5261 into the VARIANT_DI and is therefore no longer necessary. Returns S_OK if 5262 successful, or DISP_E_OVERFLOW if the represented value is too big to fit into 5263 a DECIMAL. */ 5264 static HRESULT VARIANT_DI_normalize(VARIANT_DI * val, int exponent2, BOOL isDouble) 5265 { 5266 HRESULT hres = S_OK; 5267 int exponent5, exponent10; 5268 5269 /* A factor of 2^exponent2 is equivalent to (10^exponent2)/(5^exponent2), and 5270 thus equal to (5^-exponent2)*(10^exponent2). After all manipulations, 5271 exponent10 might be used to set the VARIANT_DI scale directly. However, 5272 the value of 5^-exponent5 must be assimilated into the VARIANT_DI. */ 5273 exponent5 = -exponent2; 5274 exponent10 = exponent2; 5275 5276 /* Handle exponent5 > 0 */ 5277 while (exponent5 > 0) { 5278 char bPrevCarryBit; 5279 char bCurrCarryBit; 5280 5281 /* In order to multiply the value represented by the VARIANT_DI by 5, it 5282 is best to multiply by 10/2. Therefore, exponent10 is incremented, and 5283 somehow the mantissa should be divided by 2. */ 5284 if ((val->bitsnum[0] & 1) == 0) { 5285 /* The mantissa is divisible by 2. Therefore the division can be done 5286 without losing significant digits. */ 5287 exponent10++; exponent5--; 5288 5289 /* Shift right */ 5290 bPrevCarryBit = val->bitsnum[2] & 1; 5291 val->bitsnum[2] >>= 1; 5292 bCurrCarryBit = val->bitsnum[1] & 1; 5293 val->bitsnum[1] = (val->bitsnum[1] >> 1) | (bPrevCarryBit ? 0x80000000 : 0); 5294 val->bitsnum[0] = (val->bitsnum[0] >> 1) | (bCurrCarryBit ? 0x80000000 : 0); 5295 } else { 5296 /* The mantissa is NOT divisible by 2. Therefore the mantissa should 5297 be multiplied by 5, unless the multiplication overflows. */ 5298 DWORD temp_bitsnum[3]; 5299 5300 exponent5--; 5301 5302 memcpy(temp_bitsnum, val->bitsnum, 3 * sizeof(DWORD)); 5303 if (0 == VARIANT_int_mulbychar(temp_bitsnum, 3, 5)) { 5304 /* Multiplication succeeded without overflow, so copy result back 5305 into VARIANT_DI */ 5306 memcpy(val->bitsnum, temp_bitsnum, 3 * sizeof(DWORD)); 5307 5308 /* Mask out 3 extraneous bits introduced by the multiply */ 5309 } else { 5310 /* Multiplication by 5 overflows. The mantissa should be divided 5311 by 2, and therefore will lose significant digits. */ 5312 exponent10++; 5313 5314 /* Shift right */ 5315 bPrevCarryBit = val->bitsnum[2] & 1; 5316 val->bitsnum[2] >>= 1; 5317 bCurrCarryBit = val->bitsnum[1] & 1; 5318 val->bitsnum[1] = (val->bitsnum[1] >> 1) | (bPrevCarryBit ? 0x80000000 : 0); 5319 val->bitsnum[0] = (val->bitsnum[0] >> 1) | (bCurrCarryBit ? 0x80000000 : 0); 5320 } 5321 } 5322 } 5323 5324 /* Handle exponent5 < 0 */ 5325 while (exponent5 < 0) { 5326 /* In order to divide the value represented by the VARIANT_DI by 5, it 5327 is best to multiply by 2/10. Therefore, exponent10 is decremented, 5328 and the mantissa should be multiplied by 2 */ 5329 if ((val->bitsnum[2] & 0x80000000) == 0) { 5330 /* The mantissa can withstand a shift-left without overflowing */ 5331 exponent10--; exponent5++; 5332 VARIANT_int_shiftleft(val->bitsnum, 3, 1); 5333 } else { 5334 /* The mantissa would overflow if shifted. Therefore it should be 5335 directly divided by 5. This will lose significant digits, unless 5336 by chance the mantissa happens to be divisible by 5 */ 5337 exponent5++; 5338 VARIANT_int_divbychar(val->bitsnum, 3, 5); 5339 } 5340 } 5341 5342 /* At this point, the mantissa has assimilated the exponent5, but the 5343 exponent10 might not be suitable for assignment. The exponent10 must be 5344 in the range [-DEC_MAX_SCALE..0], so the mantissa must be scaled up or 5345 down appropriately. */ 5346 while (hres == S_OK && exponent10 > 0) { 5347 /* In order to bring exponent10 down to 0, the mantissa should be 5348 multiplied by 10 to compensate. If the exponent10 is too big, this 5349 will cause the mantissa to overflow. */ 5350 if (0 == VARIANT_int_mulbychar(val->bitsnum, 3, 10)) { 5351 exponent10--; 5352 } else { 5353 hres = DISP_E_OVERFLOW; 5354 } 5355 } 5356 while (exponent10 < -DEC_MAX_SCALE) { 5357 int rem10; 5358 /* In order to bring exponent up to -DEC_MAX_SCALE, the mantissa should 5359 be divided by 10 to compensate. If the exponent10 is too small, this 5360 will cause the mantissa to underflow and become 0 */ 5361 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10); 5362 exponent10++; 5363 if (VARIANT_int_iszero(val->bitsnum, 3)) { 5364 /* Underflow, unable to keep dividing */ 5365 exponent10 = 0; 5366 } else if (rem10 >= 5) { 5367 DWORD x = 1; 5368 VARIANT_int_add(val->bitsnum, 3, &x, 1); 5369 } 5370 } 5371 /* This step is required in order to remove excess bits of precision from the 5372 end of the bit representation, down to the precision guaranteed by the 5373 floating point number. */ 5374 if (isDouble) { 5375 while (exponent10 < 0 && (val->bitsnum[2] != 0 || (val->bitsnum[1] & 0xFFE00000) != 0)) { 5376 int rem10; 5377 5378 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10); 5379 exponent10++; 5380 if (rem10 >= 5) { 5381 DWORD x = 1; 5382 VARIANT_int_add(val->bitsnum, 3, &x, 1); 5383 } 5384 } 5385 } else { 5386 while (exponent10 < 0 && (val->bitsnum[2] != 0 || val->bitsnum[1] != 0 || 5387 (val->bitsnum[2] == 0 && val->bitsnum[1] == 0 && (val->bitsnum[0] & 0xFF000000) != 0))) { 5388 int rem10; 5389 5390 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10); 5391 exponent10++; 5392 if (rem10 >= 5) { 5393 DWORD x = 1; 5394 VARIANT_int_add(val->bitsnum, 3, &x, 1); 5395 } 5396 } 5397 } 5398 /* Remove multiples of 10 from the representation */ 5399 while (exponent10 < 0) { 5400 DWORD temp_bitsnum[3]; 5401 5402 memcpy(temp_bitsnum, val->bitsnum, 3 * sizeof(DWORD)); 5403 if (0 == VARIANT_int_divbychar(temp_bitsnum, 3, 10)) { 5404 exponent10++; 5405 memcpy(val->bitsnum, temp_bitsnum, 3 * sizeof(DWORD)); 5406 } else break; 5407 } 5408 5409 /* Scale assignment */ 5410 if (hres == S_OK) val->scale = -exponent10; 5411 5412 return hres; 5413 } 5414 5415 typedef union 5416 { 5417 struct 5418 { 5419 unsigned int m : 23; 5420 unsigned int exp_bias : 8; 5421 unsigned int sign : 1; 5422 } i; 5423 float f; 5424 } R4_FIELDS; 5425 5426 /* Convert a 32-bit floating point number into a DECIMAL, without using an 5427 intermediate string step. */ 5428 static HRESULT VARIANT_DI_FromR4(float source, VARIANT_DI * dest) 5429 { 5430 HRESULT hres = S_OK; 5431 R4_FIELDS fx; 5432 5433 fx.f = source; 5434 5435 /* Detect special cases */ 5436 if (fx.i.m == 0 && fx.i.exp_bias == 0) { 5437 /* Floating-point zero */ 5438 VARIANT_DI_clear(dest); 5439 } else if (fx.i.m == 0 && fx.i.exp_bias == 0xFF) { 5440 /* Floating-point infinity */ 5441 hres = DISP_E_OVERFLOW; 5442 } else if (fx.i.exp_bias == 0xFF) { 5443 /* Floating-point NaN */ 5444 hres = DISP_E_BADVARTYPE; 5445 } else { 5446 int exponent2; 5447 VARIANT_DI_clear(dest); 5448 5449 exponent2 = fx.i.exp_bias - 127; /* Get unbiased exponent */ 5450 dest->sign = fx.i.sign; /* Sign is simply copied */ 5451 5452 /* Copy significant bits to VARIANT_DI mantissa */ 5453 dest->bitsnum[0] = fx.i.m; 5454 dest->bitsnum[0] &= 0x007FFFFF; 5455 if (fx.i.exp_bias == 0) { 5456 /* Denormalized number - correct exponent */ 5457 exponent2++; 5458 } else { 5459 /* Add hidden bit to mantissa */ 5460 dest->bitsnum[0] |= 0x00800000; 5461 } 5462 5463 /* The act of copying a FP mantissa as integer bits is equivalent to 5464 shifting left the mantissa 23 bits. The exponent2 is reduced to 5465 compensate. */ 5466 exponent2 -= 23; 5467 5468 hres = VARIANT_DI_normalize(dest, exponent2, FALSE); 5469 } 5470 5471 return hres; 5472 } 5473 5474 typedef union 5475 { 5476 struct 5477 { 5478 unsigned int m_lo : 32; /* 52 bits of precision */ 5479 unsigned int m_hi : 20; 5480 unsigned int exp_bias : 11; /* bias == 1023 */ 5481 unsigned int sign : 1; 5482 } i; 5483 double d; 5484 } R8_FIELDS; 5485 5486 /* Convert a 64-bit floating point number into a DECIMAL, without using an 5487 intermediate string step. */ 5488 static HRESULT VARIANT_DI_FromR8(double source, VARIANT_DI * dest) 5489 { 5490 HRESULT hres = S_OK; 5491 R8_FIELDS fx; 5492 5493 fx.d = source; 5494 5495 /* Detect special cases */ 5496 if (fx.i.m_lo == 0 && fx.i.m_hi == 0 && fx.i.exp_bias == 0) { 5497 /* Floating-point zero */ 5498 VARIANT_DI_clear(dest); 5499 } else if (fx.i.m_lo == 0 && fx.i.m_hi == 0 && fx.i.exp_bias == 0x7FF) { 5500 /* Floating-point infinity */ 5501 hres = DISP_E_OVERFLOW; 5502 } else if (fx.i.exp_bias == 0x7FF) { 5503 /* Floating-point NaN */ 5504 hres = DISP_E_BADVARTYPE; 5505 } else { 5506 int exponent2; 5507 VARIANT_DI_clear(dest); 5508 5509 exponent2 = fx.i.exp_bias - 1023; /* Get unbiased exponent */ 5510 dest->sign = fx.i.sign; /* Sign is simply copied */ 5511 5512 /* Copy significant bits to VARIANT_DI mantissa */ 5513 dest->bitsnum[0] = fx.i.m_lo; 5514 dest->bitsnum[1] = fx.i.m_hi; 5515 dest->bitsnum[1] &= 0x000FFFFF; 5516 if (fx.i.exp_bias == 0) { 5517 /* Denormalized number - correct exponent */ 5518 exponent2++; 5519 } else { 5520 /* Add hidden bit to mantissa */ 5521 dest->bitsnum[1] |= 0x00100000; 5522 } 5523 5524 /* The act of copying a FP mantissa as integer bits is equivalent to 5525 shifting left the mantissa 52 bits. The exponent2 is reduced to 5526 compensate. */ 5527 exponent2 -= 52; 5528 5529 hres = VARIANT_DI_normalize(dest, exponent2, TRUE); 5530 } 5531 5532 return hres; 5533 } 5534 5535 static HRESULT VARIANT_do_division(const DECIMAL *pDecLeft, const DECIMAL *pDecRight, DECIMAL *pDecOut, 5536 BOOL round) 5537 { 5538 HRESULT hRet = S_OK; 5539 VARIANT_DI di_left, di_right, di_result; 5540 HRESULT divresult; 5541 5542 VARIANT_DIFromDec(pDecLeft, &di_left); 5543 VARIANT_DIFromDec(pDecRight, &di_right); 5544 divresult = VARIANT_DI_div(&di_left, &di_right, &di_result, round); 5545 if (divresult != S_OK) 5546 { 5547 /* division actually overflowed */ 5548 hRet = divresult; 5549 } 5550 else 5551 { 5552 hRet = S_OK; 5553 5554 if (di_result.scale > DEC_MAX_SCALE) 5555 { 5556 unsigned char remainder = 0; 5557 5558 /* division underflowed. In order to comply with the MSDN 5559 specifications for DECIMAL ranges, some significant digits 5560 must be removed 5561 */ 5562 WARN("result scale is %u, scaling (with loss of significant digits)...\n", 5563 di_result.scale); 5564 while (di_result.scale > DEC_MAX_SCALE && 5565 !VARIANT_int_iszero(di_result.bitsnum, sizeof(di_result.bitsnum) / sizeof(DWORD))) 5566 { 5567 remainder = VARIANT_int_divbychar(di_result.bitsnum, sizeof(di_result.bitsnum) / sizeof(DWORD), 10); 5568 di_result.scale--; 5569 } 5570 if (di_result.scale > DEC_MAX_SCALE) 5571 { 5572 WARN("result underflowed, setting to 0\n"); 5573 di_result.scale = 0; 5574 di_result.sign = 0; 5575 } 5576 else if (remainder >= 5) /* round up result - native oleaut32 does this */ 5577 { 5578 unsigned int i; 5579 for (remainder = 1, i = 0; i < sizeof(di_result.bitsnum) / sizeof(DWORD) && remainder; i++) { 5580 ULONGLONG digit = di_result.bitsnum[i] + 1; 5581 remainder = (digit > 0xFFFFFFFF) ? 1 : 0; 5582 di_result.bitsnum[i] = digit & 0xFFFFFFFF; 5583 } 5584 } 5585 } 5586 VARIANT_DecFromDI(&di_result, pDecOut); 5587 } 5588 return hRet; 5589 } 5590 5591 /************************************************************************ 5592 * VarDecDiv (OLEAUT32.178) 5593 * 5594 * Divide one DECIMAL by another. 5595 * 5596 * PARAMS 5597 * pDecLeft [I] Source 5598 * pDecRight [I] Value to divide by 5599 * pDecOut [O] Destination 5600 * 5601 * RETURNS 5602 * Success: S_OK. 5603 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 5604 */ 5605 HRESULT WINAPI VarDecDiv(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut) 5606 { 5607 if (!pDecLeft || !pDecRight || !pDecOut) return E_INVALIDARG; 5608 5609 return VARIANT_do_division(pDecLeft, pDecRight, pDecOut, FALSE); 5610 } 5611 5612 /************************************************************************ 5613 * VarDecMul (OLEAUT32.179) 5614 * 5615 * Multiply one DECIMAL by another. 5616 * 5617 * PARAMS 5618 * pDecLeft [I] Source 5619 * pDecRight [I] Value to multiply by 5620 * pDecOut [O] Destination 5621 * 5622 * RETURNS 5623 * Success: S_OK. 5624 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 5625 */ 5626 HRESULT WINAPI VarDecMul(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut) 5627 { 5628 HRESULT hRet = S_OK; 5629 VARIANT_DI di_left, di_right, di_result; 5630 int mulresult; 5631 5632 VARIANT_DIFromDec(pDecLeft, &di_left); 5633 VARIANT_DIFromDec(pDecRight, &di_right); 5634 mulresult = VARIANT_DI_mul(&di_left, &di_right, &di_result); 5635 if (mulresult) 5636 { 5637 /* multiplication actually overflowed */ 5638 hRet = DISP_E_OVERFLOW; 5639 } 5640 else 5641 { 5642 if (di_result.scale > DEC_MAX_SCALE) 5643 { 5644 /* multiplication underflowed. In order to comply with the MSDN 5645 specifications for DECIMAL ranges, some significant digits 5646 must be removed 5647 */ 5648 WARN("result scale is %u, scaling (with loss of significant digits)...\n", 5649 di_result.scale); 5650 while (di_result.scale > DEC_MAX_SCALE && 5651 !VARIANT_int_iszero(di_result.bitsnum, sizeof(di_result.bitsnum)/sizeof(DWORD))) 5652 { 5653 VARIANT_int_divbychar(di_result.bitsnum, sizeof(di_result.bitsnum)/sizeof(DWORD), 10); 5654 di_result.scale--; 5655 } 5656 if (di_result.scale > DEC_MAX_SCALE) 5657 { 5658 WARN("result underflowed, setting to 0\n"); 5659 di_result.scale = 0; 5660 di_result.sign = 0; 5661 } 5662 } 5663 VARIANT_DecFromDI(&di_result, pDecOut); 5664 } 5665 return hRet; 5666 } 5667 5668 /************************************************************************ 5669 * VarDecSub (OLEAUT32.181) 5670 * 5671 * Subtract one DECIMAL from another. 5672 * 5673 * PARAMS 5674 * pDecLeft [I] Source 5675 * pDecRight [I] DECIMAL to subtract from pDecLeft 5676 * pDecOut [O] Destination 5677 * 5678 * RETURNS 5679 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 5680 */ 5681 HRESULT WINAPI VarDecSub(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut) 5682 { 5683 DECIMAL decRight; 5684 5685 /* Implement as addition of the negative */ 5686 VarDecNeg(pDecRight, &decRight); 5687 return VarDecAdd(pDecLeft, &decRight, pDecOut); 5688 } 5689 5690 /************************************************************************ 5691 * VarDecAbs (OLEAUT32.182) 5692 * 5693 * Convert a DECIMAL into its absolute value. 5694 * 5695 * PARAMS 5696 * pDecIn [I] Source 5697 * pDecOut [O] Destination 5698 * 5699 * RETURNS 5700 * S_OK. This function does not fail. 5701 */ 5702 HRESULT WINAPI VarDecAbs(const DECIMAL* pDecIn, DECIMAL* pDecOut) 5703 { 5704 *pDecOut = *pDecIn; 5705 DEC_SIGN(pDecOut) &= ~DECIMAL_NEG; 5706 return S_OK; 5707 } 5708 5709 /************************************************************************ 5710 * VarDecFix (OLEAUT32.187) 5711 * 5712 * Return the integer portion of a DECIMAL. 5713 * 5714 * PARAMS 5715 * pDecIn [I] Source 5716 * pDecOut [O] Destination 5717 * 5718 * RETURNS 5719 * Success: S_OK. 5720 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 5721 * 5722 * NOTES 5723 * - The difference between this function and VarDecInt() is that VarDecInt() rounds 5724 * negative numbers away from 0, while this function rounds them towards zero. 5725 */ 5726 HRESULT WINAPI VarDecFix(const DECIMAL* pDecIn, DECIMAL* pDecOut) 5727 { 5728 double dbl; 5729 HRESULT hr; 5730 5731 if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG) 5732 return E_INVALIDARG; 5733 5734 if (!DEC_SCALE(pDecIn)) 5735 { 5736 *pDecOut = *pDecIn; /* Already an integer */ 5737 return S_OK; 5738 } 5739 5740 hr = VarR8FromDec(pDecIn, &dbl); 5741 if (SUCCEEDED(hr)) { 5742 LONGLONG rounded = dbl; 5743 5744 hr = VarDecFromI8(rounded, pDecOut); 5745 } 5746 return hr; 5747 } 5748 5749 /************************************************************************ 5750 * VarDecInt (OLEAUT32.188) 5751 * 5752 * Return the integer portion of a DECIMAL. 5753 * 5754 * PARAMS 5755 * pDecIn [I] Source 5756 * pDecOut [O] Destination 5757 * 5758 * RETURNS 5759 * Success: S_OK. 5760 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 5761 * 5762 * NOTES 5763 * - The difference between this function and VarDecFix() is that VarDecFix() rounds 5764 * negative numbers towards 0, while this function rounds them away from zero. 5765 */ 5766 HRESULT WINAPI VarDecInt(const DECIMAL* pDecIn, DECIMAL* pDecOut) 5767 { 5768 double dbl; 5769 HRESULT hr; 5770 5771 if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG) 5772 return E_INVALIDARG; 5773 5774 if (!(DEC_SIGN(pDecIn) & DECIMAL_NEG) || !DEC_SCALE(pDecIn)) 5775 return VarDecFix(pDecIn, pDecOut); /* The same, if +ve or no fractionals */ 5776 5777 hr = VarR8FromDec(pDecIn, &dbl); 5778 if (SUCCEEDED(hr)) { 5779 LONGLONG rounded = dbl >= 0.0 ? dbl + 0.5 : dbl - 0.5; 5780 5781 hr = VarDecFromI8(rounded, pDecOut); 5782 } 5783 return hr; 5784 } 5785 5786 /************************************************************************ 5787 * VarDecNeg (OLEAUT32.189) 5788 * 5789 * Change the sign of a DECIMAL. 5790 * 5791 * PARAMS 5792 * pDecIn [I] Source 5793 * pDecOut [O] Destination 5794 * 5795 * RETURNS 5796 * S_OK. This function does not fail. 5797 */ 5798 HRESULT WINAPI VarDecNeg(const DECIMAL* pDecIn, DECIMAL* pDecOut) 5799 { 5800 *pDecOut = *pDecIn; 5801 DEC_SIGN(pDecOut) ^= DECIMAL_NEG; 5802 return S_OK; 5803 } 5804 5805 /************************************************************************ 5806 * VarDecRound (OLEAUT32.203) 5807 * 5808 * Change the precision of a DECIMAL. 5809 * 5810 * PARAMS 5811 * pDecIn [I] Source 5812 * cDecimals [I] New number of decimals to keep 5813 * pDecOut [O] Destination 5814 * 5815 * RETURNS 5816 * Success: S_OK. pDecOut contains the rounded value. 5817 * Failure: E_INVALIDARG if any argument is invalid. 5818 */ 5819 HRESULT WINAPI VarDecRound(const DECIMAL* pDecIn, int cDecimals, DECIMAL* pDecOut) 5820 { 5821 DECIMAL divisor, tmp; 5822 HRESULT hr; 5823 unsigned int i; 5824 5825 if (cDecimals < 0 || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG) || DEC_SCALE(pDecIn) > DEC_MAX_SCALE) 5826 return E_INVALIDARG; 5827 5828 if (cDecimals >= DEC_SCALE(pDecIn)) 5829 { 5830 *pDecOut = *pDecIn; /* More precision than we have */ 5831 return S_OK; 5832 } 5833 5834 /* truncate significant digits and rescale */ 5835 memset(&divisor, 0, sizeof(divisor)); 5836 DEC_LO64(&divisor) = 1; 5837 5838 memset(&tmp, 0, sizeof(tmp)); 5839 DEC_LO64(&tmp) = 10; 5840 for (i = 0; i < DEC_SCALE(pDecIn) - cDecimals; ++i) 5841 { 5842 hr = VarDecMul(&divisor, &tmp, &divisor); 5843 if (FAILED(hr)) 5844 return hr; 5845 } 5846 5847 hr = VARIANT_do_division(pDecIn, &divisor, pDecOut, TRUE); 5848 if (FAILED(hr)) 5849 return hr; 5850 5851 DEC_SCALE(pDecOut) = cDecimals; 5852 5853 return S_OK; 5854 } 5855 5856 /************************************************************************ 5857 * VarDecCmp (OLEAUT32.204) 5858 * 5859 * Compare two DECIMAL values. 5860 * 5861 * PARAMS 5862 * pDecLeft [I] Source 5863 * pDecRight [I] Value to compare 5864 * 5865 * RETURNS 5866 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pDecLeft 5867 * is less than, equal to or greater than pDecRight respectively. 5868 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison 5869 */ 5870 HRESULT WINAPI VarDecCmp(const DECIMAL* pDecLeft, const DECIMAL* pDecRight) 5871 { 5872 HRESULT hRet; 5873 DECIMAL result; 5874 5875 if (!pDecLeft || !pDecRight) 5876 return VARCMP_NULL; 5877 5878 if ((!(DEC_SIGN(pDecLeft) & DECIMAL_NEG)) && (DEC_SIGN(pDecRight) & DECIMAL_NEG) && 5879 (DEC_HI32(pDecLeft) | DEC_MID32(pDecLeft) | DEC_LO32(pDecLeft))) 5880 return VARCMP_GT; 5881 else if ((DEC_SIGN(pDecLeft) & DECIMAL_NEG) && (!(DEC_SIGN(pDecRight) & DECIMAL_NEG)) && 5882 (DEC_HI32(pDecLeft) | DEC_MID32(pDecLeft) | DEC_LO32(pDecLeft))) 5883 return VARCMP_LT; 5884 5885 /* Subtract right from left, and compare the result to 0 */ 5886 hRet = VarDecSub(pDecLeft, pDecRight, &result); 5887 5888 if (SUCCEEDED(hRet)) 5889 { 5890 int non_zero = DEC_HI32(&result) | DEC_MID32(&result) | DEC_LO32(&result); 5891 5892 if ((DEC_SIGN(&result) & DECIMAL_NEG) && non_zero) 5893 hRet = (HRESULT)VARCMP_LT; 5894 else if (non_zero) 5895 hRet = (HRESULT)VARCMP_GT; 5896 else 5897 hRet = (HRESULT)VARCMP_EQ; 5898 } 5899 return hRet; 5900 } 5901 5902 /************************************************************************ 5903 * VarDecCmpR8 (OLEAUT32.298) 5904 * 5905 * Compare a DECIMAL to a double 5906 * 5907 * PARAMS 5908 * pDecLeft [I] DECIMAL Source 5909 * dblRight [I] double to compare to pDecLeft 5910 * 5911 * RETURNS 5912 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight 5913 * is less than, equal to or greater than pDecLeft respectively. 5914 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison 5915 */ 5916 HRESULT WINAPI VarDecCmpR8(const DECIMAL* pDecLeft, double dblRight) 5917 { 5918 HRESULT hRet; 5919 DECIMAL decRight; 5920 5921 hRet = VarDecFromR8(dblRight, &decRight); 5922 5923 if (SUCCEEDED(hRet)) 5924 hRet = VarDecCmp(pDecLeft, &decRight); 5925 5926 return hRet; 5927 } 5928 5929 /* BOOL 5930 */ 5931 5932 /************************************************************************ 5933 * VarBoolFromUI1 (OLEAUT32.118) 5934 * 5935 * Convert a VT_UI1 to a VT_BOOL. 5936 * 5937 * PARAMS 5938 * bIn [I] Source 5939 * pBoolOut [O] Destination 5940 * 5941 * RETURNS 5942 * S_OK. 5943 */ 5944 HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL *pBoolOut) 5945 { 5946 *pBoolOut = bIn ? VARIANT_TRUE : VARIANT_FALSE; 5947 return S_OK; 5948 } 5949 5950 /************************************************************************ 5951 * VarBoolFromI2 (OLEAUT32.119) 5952 * 5953 * Convert a VT_I2 to a VT_BOOL. 5954 * 5955 * PARAMS 5956 * sIn [I] Source 5957 * pBoolOut [O] Destination 5958 * 5959 * RETURNS 5960 * S_OK. 5961 */ 5962 HRESULT WINAPI VarBoolFromI2(SHORT sIn, VARIANT_BOOL *pBoolOut) 5963 { 5964 *pBoolOut = sIn ? VARIANT_TRUE : VARIANT_FALSE; 5965 return S_OK; 5966 } 5967 5968 /************************************************************************ 5969 * VarBoolFromI4 (OLEAUT32.120) 5970 * 5971 * Convert a VT_I4 to a VT_BOOL. 5972 * 5973 * PARAMS 5974 * sIn [I] Source 5975 * pBoolOut [O] Destination 5976 * 5977 * RETURNS 5978 * S_OK. 5979 */ 5980 HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL *pBoolOut) 5981 { 5982 *pBoolOut = lIn ? VARIANT_TRUE : VARIANT_FALSE; 5983 return S_OK; 5984 } 5985 5986 /************************************************************************ 5987 * VarBoolFromR4 (OLEAUT32.121) 5988 * 5989 * Convert a VT_R4 to a VT_BOOL. 5990 * 5991 * PARAMS 5992 * fltIn [I] Source 5993 * pBoolOut [O] Destination 5994 * 5995 * RETURNS 5996 * S_OK. 5997 */ 5998 HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL *pBoolOut) 5999 { 6000 *pBoolOut = fltIn ? VARIANT_TRUE : VARIANT_FALSE; 6001 return S_OK; 6002 } 6003 6004 /************************************************************************ 6005 * VarBoolFromR8 (OLEAUT32.122) 6006 * 6007 * Convert a VT_R8 to a VT_BOOL. 6008 * 6009 * PARAMS 6010 * dblIn [I] Source 6011 * pBoolOut [O] Destination 6012 * 6013 * RETURNS 6014 * S_OK. 6015 */ 6016 HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL *pBoolOut) 6017 { 6018 *pBoolOut = dblIn ? VARIANT_TRUE : VARIANT_FALSE; 6019 return S_OK; 6020 } 6021 6022 /************************************************************************ 6023 * VarBoolFromDate (OLEAUT32.123) 6024 * 6025 * Convert a VT_DATE to a VT_BOOL. 6026 * 6027 * PARAMS 6028 * dateIn [I] Source 6029 * pBoolOut [O] Destination 6030 * 6031 * RETURNS 6032 * S_OK. 6033 */ 6034 HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL *pBoolOut) 6035 { 6036 *pBoolOut = dateIn ? VARIANT_TRUE : VARIANT_FALSE; 6037 return S_OK; 6038 } 6039 6040 /************************************************************************ 6041 * VarBoolFromCy (OLEAUT32.124) 6042 * 6043 * Convert a VT_CY to a VT_BOOL. 6044 * 6045 * PARAMS 6046 * cyIn [I] Source 6047 * pBoolOut [O] Destination 6048 * 6049 * RETURNS 6050 * S_OK. 6051 */ 6052 HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL *pBoolOut) 6053 { 6054 *pBoolOut = cyIn.int64 ? VARIANT_TRUE : VARIANT_FALSE; 6055 return S_OK; 6056 } 6057 6058 /************************************************************************ 6059 * VARIANT_GetLocalisedText [internal] 6060 * 6061 * Get a localized string from the resources 6062 * 6063 */ 6064 static BOOL VARIANT_GetLocalisedText(LANGID langId, DWORD dwId, WCHAR *lpszDest) 6065 { 6066 HRSRC hrsrc; 6067 6068 hrsrc = FindResourceExW( hProxyDll, (LPWSTR)RT_STRING, 6069 MAKEINTRESOURCEW((dwId >> 4) + 1), langId ); 6070 if (hrsrc) 6071 { 6072 HGLOBAL hmem = LoadResource( hProxyDll, hrsrc ); 6073 6074 if (hmem) 6075 { 6076 const WCHAR *p; 6077 unsigned int i; 6078 6079 p = LockResource( hmem ); 6080 for (i = 0; i < (dwId & 0x0f); i++) p += *p + 1; 6081 6082 memcpy( lpszDest, p + 1, *p * sizeof(WCHAR) ); 6083 lpszDest[*p] = '\0'; 6084 TRACE("got %s for LANGID %08x\n", debugstr_w(lpszDest), langId); 6085 return TRUE; 6086 } 6087 } 6088 return FALSE; 6089 } 6090 6091 /************************************************************************ 6092 * VarBoolFromStr (OLEAUT32.125) 6093 * 6094 * Convert a VT_BSTR to a VT_BOOL. 6095 * 6096 * PARAMS 6097 * strIn [I] Source 6098 * lcid [I] LCID for the conversion 6099 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 6100 * pBoolOut [O] Destination 6101 * 6102 * RETURNS 6103 * Success: S_OK. 6104 * Failure: E_INVALIDARG, if pBoolOut is invalid. 6105 * DISP_E_TYPEMISMATCH, if the type cannot be converted 6106 * 6107 * NOTES 6108 * - strIn will be recognised if it contains "#TRUE#" or "#FALSE#". Additionally, 6109 * it may contain (in any case mapping) the text "true" or "false". 6110 * - If dwFlags includes VAR_LOCALBOOL, then the text may also match the 6111 * localised text of "True" or "False" in the language specified by lcid. 6112 * - If none of these matches occur, the string is treated as a numeric string 6113 * and the boolean pBoolOut will be set according to whether the number is zero 6114 * or not. The dwFlags parameter is passed to VarR8FromStr() for this conversion. 6115 * - If the text is not numeric and does not match any of the above, then 6116 * DISP_E_TYPEMISMATCH is returned. 6117 */ 6118 HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL *pBoolOut) 6119 { 6120 /* Any VB/VBA programmers out there should recognise these strings... */ 6121 static const WCHAR szFalse[] = { '#','F','A','L','S','E','#','\0' }; 6122 static const WCHAR szTrue[] = { '#','T','R','U','E','#','\0' }; 6123 WCHAR szBuff[64]; 6124 LANGID langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); 6125 HRESULT hRes = S_OK; 6126 6127 if (!strIn || !pBoolOut) 6128 return DISP_E_TYPEMISMATCH; 6129 6130 /* Check if we should be comparing against localised text */ 6131 if (dwFlags & VAR_LOCALBOOL) 6132 { 6133 /* Convert our LCID into a usable value */ 6134 lcid = ConvertDefaultLocale(lcid); 6135 6136 langId = LANGIDFROMLCID(lcid); 6137 6138 if (PRIMARYLANGID(langId) == LANG_NEUTRAL) 6139 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); 6140 6141 /* Note: Native oleaut32 always copies strIn and maps halfwidth characters. 6142 * I don't think this is needed unless any of the localised text strings 6143 * contain characters that can be so mapped. In the event that this is 6144 * true for a given language (possibly some Asian languages), then strIn 6145 * should be mapped here _only_ if langId is an Id for which this can occur. 6146 */ 6147 } 6148 6149 /* Note that if we are not comparing against localised strings, langId 6150 * will have its default value of LANG_ENGLISH. This allows us to mimic 6151 * the native behaviour of always checking against English strings even 6152 * after we've checked for localised ones. 6153 */ 6154 VarBoolFromStr_CheckLocalised: 6155 if (VARIANT_GetLocalisedText(langId, IDS_TRUE, szBuff)) 6156 { 6157 /* Compare against localised strings, ignoring case */ 6158 if (!strcmpiW(strIn, szBuff)) 6159 { 6160 *pBoolOut = VARIANT_TRUE; /* Matched localised 'true' text */ 6161 return hRes; 6162 } 6163 VARIANT_GetLocalisedText(langId, IDS_FALSE, szBuff); 6164 if (!strcmpiW(strIn, szBuff)) 6165 { 6166 *pBoolOut = VARIANT_FALSE; /* Matched localised 'false' text */ 6167 return hRes; 6168 } 6169 } 6170 6171 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT)) 6172 { 6173 /* We have checked the localised text, now check English */ 6174 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); 6175 goto VarBoolFromStr_CheckLocalised; 6176 } 6177 6178 /* All checks against localised text have failed, try #TRUE#/#FALSE# */ 6179 if (!strcmpW(strIn, szFalse)) 6180 *pBoolOut = VARIANT_FALSE; 6181 else if (!strcmpW(strIn, szTrue)) 6182 *pBoolOut = VARIANT_TRUE; 6183 else 6184 { 6185 double d; 6186 6187 /* If this string is a number, convert it as one */ 6188 hRes = VarR8FromStr(strIn, lcid, dwFlags, &d); 6189 if (SUCCEEDED(hRes)) *pBoolOut = d ? VARIANT_TRUE : VARIANT_FALSE; 6190 } 6191 return hRes; 6192 } 6193 6194 /************************************************************************ 6195 * VarBoolFromDisp (OLEAUT32.126) 6196 * 6197 * Convert a VT_DISPATCH to a VT_BOOL. 6198 * 6199 * PARAMS 6200 * pdispIn [I] Source 6201 * lcid [I] LCID for conversion 6202 * pBoolOut [O] Destination 6203 * 6204 * RETURNS 6205 * Success: S_OK. 6206 * Failure: E_INVALIDARG, if the source value is invalid 6207 * DISP_E_OVERFLOW, if the value will not fit in the destination 6208 * DISP_E_TYPEMISMATCH, if the type cannot be converted 6209 */ 6210 HRESULT WINAPI VarBoolFromDisp(IDispatch* pdispIn, LCID lcid, VARIANT_BOOL *pBoolOut) 6211 { 6212 return VARIANT_FromDisp(pdispIn, lcid, pBoolOut, VT_BOOL, 0); 6213 } 6214 6215 /************************************************************************ 6216 * VarBoolFromI1 (OLEAUT32.233) 6217 * 6218 * Convert a VT_I1 to a VT_BOOL. 6219 * 6220 * PARAMS 6221 * cIn [I] Source 6222 * pBoolOut [O] Destination 6223 * 6224 * RETURNS 6225 * S_OK. 6226 */ 6227 HRESULT WINAPI VarBoolFromI1(signed char cIn, VARIANT_BOOL *pBoolOut) 6228 { 6229 *pBoolOut = cIn ? VARIANT_TRUE : VARIANT_FALSE; 6230 return S_OK; 6231 } 6232 6233 /************************************************************************ 6234 * VarBoolFromUI2 (OLEAUT32.234) 6235 * 6236 * Convert a VT_UI2 to a VT_BOOL. 6237 * 6238 * PARAMS 6239 * usIn [I] Source 6240 * pBoolOut [O] Destination 6241 * 6242 * RETURNS 6243 * S_OK. 6244 */ 6245 HRESULT WINAPI VarBoolFromUI2(USHORT usIn, VARIANT_BOOL *pBoolOut) 6246 { 6247 *pBoolOut = usIn ? VARIANT_TRUE : VARIANT_FALSE; 6248 return S_OK; 6249 } 6250 6251 /************************************************************************ 6252 * VarBoolFromUI4 (OLEAUT32.235) 6253 * 6254 * Convert a VT_UI4 to a VT_BOOL. 6255 * 6256 * PARAMS 6257 * ulIn [I] Source 6258 * pBoolOut [O] Destination 6259 * 6260 * RETURNS 6261 * S_OK. 6262 */ 6263 HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL *pBoolOut) 6264 { 6265 *pBoolOut = ulIn ? VARIANT_TRUE : VARIANT_FALSE; 6266 return S_OK; 6267 } 6268 6269 /************************************************************************ 6270 * VarBoolFromDec (OLEAUT32.236) 6271 * 6272 * Convert a VT_DECIMAL to a VT_BOOL. 6273 * 6274 * PARAMS 6275 * pDecIn [I] Source 6276 * pBoolOut [O] Destination 6277 * 6278 * RETURNS 6279 * Success: S_OK. 6280 * Failure: E_INVALIDARG, if pDecIn is invalid. 6281 */ 6282 HRESULT WINAPI VarBoolFromDec(DECIMAL* pDecIn, VARIANT_BOOL *pBoolOut) 6283 { 6284 if (DEC_SCALE(pDecIn) > DEC_MAX_SCALE || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)) 6285 return E_INVALIDARG; 6286 6287 if (DEC_HI32(pDecIn) || DEC_MID32(pDecIn) || DEC_LO32(pDecIn)) 6288 *pBoolOut = VARIANT_TRUE; 6289 else 6290 *pBoolOut = VARIANT_FALSE; 6291 return S_OK; 6292 } 6293 6294 /************************************************************************ 6295 * VarBoolFromI8 (OLEAUT32.370) 6296 * 6297 * Convert a VT_I8 to a VT_BOOL. 6298 * 6299 * PARAMS 6300 * ullIn [I] Source 6301 * pBoolOut [O] Destination 6302 * 6303 * RETURNS 6304 * S_OK. 6305 */ 6306 HRESULT WINAPI VarBoolFromI8(LONG64 llIn, VARIANT_BOOL *pBoolOut) 6307 { 6308 *pBoolOut = llIn ? VARIANT_TRUE : VARIANT_FALSE; 6309 return S_OK; 6310 } 6311 6312 /************************************************************************ 6313 * VarBoolFromUI8 (OLEAUT32.371) 6314 * 6315 * Convert a VT_UI8 to a VT_BOOL. 6316 * 6317 * PARAMS 6318 * ullIn [I] Source 6319 * pBoolOut [O] Destination 6320 * 6321 * RETURNS 6322 * S_OK. 6323 */ 6324 HRESULT WINAPI VarBoolFromUI8(ULONG64 ullIn, VARIANT_BOOL *pBoolOut) 6325 { 6326 *pBoolOut = ullIn ? VARIANT_TRUE : VARIANT_FALSE; 6327 return S_OK; 6328 } 6329 6330 /* BSTR 6331 */ 6332 6333 /* Write a number from a UI8 and sign */ 6334 static WCHAR *VARIANT_WriteNumber(ULONG64 ulVal, WCHAR* szOut) 6335 { 6336 do 6337 { 6338 WCHAR ulNextDigit = ulVal % 10; 6339 6340 *szOut-- = '0' + ulNextDigit; 6341 ulVal = (ulVal - ulNextDigit) / 10; 6342 } while (ulVal); 6343 6344 szOut++; 6345 return szOut; 6346 } 6347 6348 /* Create a (possibly localised) BSTR from a UI8 and sign */ 6349 static BSTR VARIANT_MakeBstr(LCID lcid, DWORD dwFlags, WCHAR *szOut) 6350 { 6351 WCHAR szConverted[256]; 6352 6353 if (dwFlags & VAR_NEGATIVE) 6354 *--szOut = '-'; 6355 6356 if (dwFlags & LOCALE_USE_NLS) 6357 { 6358 /* Format the number for the locale */ 6359 szConverted[0] = '\0'; 6360 GetNumberFormatW(lcid, 6361 dwFlags & LOCALE_NOUSEROVERRIDE, 6362 szOut, NULL, szConverted, sizeof(szConverted)/sizeof(WCHAR)); 6363 szOut = szConverted; 6364 } 6365 return SysAllocStringByteLen((LPCSTR)szOut, strlenW(szOut) * sizeof(WCHAR)); 6366 } 6367 6368 /* Create a (possibly localised) BSTR from a UI8 and sign */ 6369 static HRESULT VARIANT_BstrFromUInt(ULONG64 ulVal, LCID lcid, DWORD dwFlags, BSTR *pbstrOut) 6370 { 6371 WCHAR szBuff[64], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1; 6372 6373 if (!pbstrOut) 6374 return E_INVALIDARG; 6375 6376 /* Create the basic number string */ 6377 *szOut-- = '\0'; 6378 szOut = VARIANT_WriteNumber(ulVal, szOut); 6379 6380 *pbstrOut = VARIANT_MakeBstr(lcid, dwFlags, szOut); 6381 TRACE("returning %s\n", debugstr_w(*pbstrOut)); 6382 return *pbstrOut ? S_OK : E_OUTOFMEMORY; 6383 } 6384 6385 /****************************************************************************** 6386 * VarBstrFromUI1 (OLEAUT32.108) 6387 * 6388 * Convert a VT_UI1 to a VT_BSTR. 6389 * 6390 * PARAMS 6391 * bIn [I] Source 6392 * lcid [I] LCID for the conversion 6393 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 6394 * pbstrOut [O] Destination 6395 * 6396 * RETURNS 6397 * Success: S_OK. 6398 * Failure: E_INVALIDARG, if pbstrOut is invalid. 6399 * E_OUTOFMEMORY, if memory allocation fails. 6400 */ 6401 HRESULT WINAPI VarBstrFromUI1(BYTE bIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) 6402 { 6403 return VARIANT_BstrFromUInt(bIn, lcid, dwFlags, pbstrOut); 6404 } 6405 6406 /****************************************************************************** 6407 * VarBstrFromI2 (OLEAUT32.109) 6408 * 6409 * Convert a VT_I2 to a VT_BSTR. 6410 * 6411 * PARAMS 6412 * sIn [I] Source 6413 * lcid [I] LCID for the conversion 6414 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 6415 * pbstrOut [O] Destination 6416 * 6417 * RETURNS 6418 * Success: S_OK. 6419 * Failure: E_INVALIDARG, if pbstrOut is invalid. 6420 * E_OUTOFMEMORY, if memory allocation fails. 6421 */ 6422 HRESULT WINAPI VarBstrFromI2(short sIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) 6423 { 6424 ULONG64 ul64 = sIn; 6425 6426 if (sIn < 0) 6427 { 6428 ul64 = -sIn; 6429 dwFlags |= VAR_NEGATIVE; 6430 } 6431 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut); 6432 } 6433 6434 /****************************************************************************** 6435 * VarBstrFromI4 (OLEAUT32.110) 6436 * 6437 * Convert a VT_I4 to a VT_BSTR. 6438 * 6439 * PARAMS 6440 * lIn [I] Source 6441 * lcid [I] LCID for the conversion 6442 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 6443 * pbstrOut [O] Destination 6444 * 6445 * RETURNS 6446 * Success: S_OK. 6447 * Failure: E_INVALIDARG, if pbstrOut is invalid. 6448 * E_OUTOFMEMORY, if memory allocation fails. 6449 */ 6450 HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) 6451 { 6452 ULONG64 ul64 = lIn; 6453 6454 if (lIn < 0) 6455 { 6456 ul64 = (ULONG)-lIn; 6457 dwFlags |= VAR_NEGATIVE; 6458 } 6459 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut); 6460 } 6461 6462 static BSTR VARIANT_BstrReplaceDecimal(const WCHAR * buff, LCID lcid, ULONG dwFlags) 6463 { 6464 BSTR bstrOut; 6465 WCHAR lpDecimalSep[16]; 6466 6467 /* Native oleaut32 uses the locale-specific decimal separator even in the 6468 absence of the LOCALE_USE_NLS flag. For example, the Spanish/Latin 6469 American locales will see "one thousand and one tenth" as "1000,1" 6470 instead of "1000.1" (notice the comma). The following code checks for 6471 the need to replace the decimal separator, and if so, will prepare an 6472 appropriate NUMBERFMTW structure to do the job via GetNumberFormatW(). 6473 */ 6474 GetLocaleInfoW(lcid, LOCALE_SDECIMAL | (dwFlags & LOCALE_NOUSEROVERRIDE), 6475 lpDecimalSep, sizeof(lpDecimalSep) / sizeof(WCHAR)); 6476 if (lpDecimalSep[0] == '.' && lpDecimalSep[1] == '\0') 6477 { 6478 /* locale is compatible with English - return original string */ 6479 bstrOut = SysAllocString(buff); 6480 } 6481 else 6482 { 6483 WCHAR *p; 6484 WCHAR numbuff[256]; 6485 WCHAR empty[] = {'\0'}; 6486 NUMBERFMTW minFormat; 6487 6488 minFormat.NumDigits = 0; 6489 minFormat.LeadingZero = 0; 6490 minFormat.Grouping = 0; 6491 minFormat.lpDecimalSep = lpDecimalSep; 6492 minFormat.lpThousandSep = empty; 6493 minFormat.NegativeOrder = 1; /* NLS_NEG_LEFT */ 6494 6495 /* count number of decimal digits in string */ 6496 p = strchrW( buff, '.' ); 6497 if (p) minFormat.NumDigits = strlenW(p + 1); 6498 6499 numbuff[0] = '\0'; 6500 if (!GetNumberFormatW(lcid, 0, buff, &minFormat, numbuff, sizeof(numbuff) / sizeof(WCHAR))) 6501 { 6502 WARN("GetNumberFormatW() failed, returning raw number string instead\n"); 6503 bstrOut = SysAllocString(buff); 6504 } 6505 else 6506 { 6507 TRACE("created minimal NLS string %s\n", debugstr_w(numbuff)); 6508 bstrOut = SysAllocString(numbuff); 6509 } 6510 } 6511 return bstrOut; 6512 } 6513 6514 static HRESULT VARIANT_BstrFromReal(DOUBLE dblIn, LCID lcid, ULONG dwFlags, 6515 BSTR* pbstrOut, LPCWSTR lpszFormat) 6516 { 6517 WCHAR buff[256]; 6518 6519 if (!pbstrOut) 6520 return E_INVALIDARG; 6521 6522 sprintfW( buff, lpszFormat, dblIn ); 6523 6524 /* Negative zeroes are disallowed (some applications depend on this). 6525 If buff starts with a minus, and then nothing follows but zeroes 6526 and/or a period, it is a negative zero and is replaced with a 6527 canonical zero. This duplicates native oleaut32 behavior. 6528 */ 6529 if (buff[0] == '-') 6530 { 6531 const WCHAR szAccept[] = {'0', '.', '\0'}; 6532 if (strlenW(buff + 1) == strspnW(buff + 1, szAccept)) 6533 { buff[0] = '0'; buff[1] = '\0'; } 6534 } 6535 6536 TRACE("created string %s\n", debugstr_w(buff)); 6537 if (dwFlags & LOCALE_USE_NLS) 6538 { 6539 WCHAR numbuff[256]; 6540 6541 /* Format the number for the locale */ 6542 numbuff[0] = '\0'; 6543 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE, 6544 buff, NULL, numbuff, sizeof(numbuff) / sizeof(WCHAR)); 6545 TRACE("created NLS string %s\n", debugstr_w(numbuff)); 6546 *pbstrOut = SysAllocString(numbuff); 6547 } 6548 else 6549 { 6550 *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags); 6551 } 6552 return *pbstrOut ? S_OK : E_OUTOFMEMORY; 6553 } 6554 6555 /****************************************************************************** 6556 * VarBstrFromR4 (OLEAUT32.111) 6557 * 6558 * Convert a VT_R4 to a VT_BSTR. 6559 * 6560 * PARAMS 6561 * fltIn [I] Source 6562 * lcid [I] LCID for the conversion 6563 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 6564 * pbstrOut [O] Destination 6565 * 6566 * RETURNS 6567 * Success: S_OK. 6568 * Failure: E_INVALIDARG, if pbstrOut is invalid. 6569 * E_OUTOFMEMORY, if memory allocation fails. 6570 */ 6571 HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) 6572 { 6573 return VARIANT_BstrFromReal(fltIn, lcid, dwFlags, pbstrOut, szFloatFormatW); 6574 } 6575 6576 /****************************************************************************** 6577 * VarBstrFromR8 (OLEAUT32.112) 6578 * 6579 * Convert a VT_R8 to a VT_BSTR. 6580 * 6581 * PARAMS 6582 * dblIn [I] Source 6583 * lcid [I] LCID for the conversion 6584 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 6585 * pbstrOut [O] Destination 6586 * 6587 * RETURNS 6588 * Success: S_OK. 6589 * Failure: E_INVALIDARG, if pbstrOut is invalid. 6590 * E_OUTOFMEMORY, if memory allocation fails. 6591 */ 6592 HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) 6593 { 6594 return VARIANT_BstrFromReal(dblIn, lcid, dwFlags, pbstrOut, szDoubleFormatW); 6595 } 6596 6597 /****************************************************************************** 6598 * VarBstrFromCy [OLEAUT32.113] 6599 * 6600 * Convert a VT_CY to a VT_BSTR. 6601 * 6602 * PARAMS 6603 * cyIn [I] Source 6604 * lcid [I] LCID for the conversion 6605 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 6606 * pbstrOut [O] Destination 6607 * 6608 * RETURNS 6609 * Success: S_OK. 6610 * Failure: E_INVALIDARG, if pbstrOut is invalid. 6611 * E_OUTOFMEMORY, if memory allocation fails. 6612 */ 6613 HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut) 6614 { 6615 WCHAR buff[256]; 6616 VARIANT_DI decVal; 6617 6618 if (!pbstrOut) 6619 return E_INVALIDARG; 6620 6621 decVal.scale = 4; 6622 decVal.sign = 0; 6623 decVal.bitsnum[0] = cyIn.s.Lo; 6624 decVal.bitsnum[1] = cyIn.s.Hi; 6625 if (cyIn.s.Hi & 0x80000000UL) { 6626 DWORD one = 1; 6627 6628 /* Negative number! */ 6629 decVal.sign = 1; 6630 decVal.bitsnum[0] = ~decVal.bitsnum[0]; 6631 decVal.bitsnum[1] = ~decVal.bitsnum[1]; 6632 VARIANT_int_add(decVal.bitsnum, 3, &one, 1); 6633 } 6634 decVal.bitsnum[2] = 0; 6635 VARIANT_DI_tostringW(&decVal, buff, sizeof(buff)/sizeof(buff[0])); 6636 6637 if (dwFlags & LOCALE_USE_NLS) 6638 { 6639 WCHAR cybuff[256]; 6640 6641 /* Format the currency for the locale */ 6642 cybuff[0] = '\0'; 6643 GetCurrencyFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE, 6644 buff, NULL, cybuff, sizeof(cybuff) / sizeof(WCHAR)); 6645 *pbstrOut = SysAllocString(cybuff); 6646 } 6647 else 6648 *pbstrOut = VARIANT_BstrReplaceDecimal(buff,lcid,dwFlags); 6649 6650 return *pbstrOut ? S_OK : E_OUTOFMEMORY; 6651 } 6652 6653 static inline int output_int_len(int o, int min_len, WCHAR *date, int date_len) 6654 { 6655 int len, tmp; 6656 6657 if(min_len >= date_len) 6658 return -1; 6659 6660 for(len=0, tmp=o; tmp; tmp/=10) len++; 6661 if(!len) len++; 6662 if(len >= date_len) 6663 return -1; 6664 6665 for(tmp=min_len-len; tmp>0; tmp--) 6666 *date++ = '0'; 6667 for(tmp=len; tmp>0; tmp--, o/=10) 6668 date[tmp-1] = '0' + o%10; 6669 return min_len>len ? min_len : len; 6670 } 6671 6672 /* format date string, similar to GetDateFormatW function but works on bigger range of dates */ 6673 BOOL get_date_format(LCID lcid, DWORD flags, const SYSTEMTIME *st, 6674 const WCHAR *fmt, WCHAR *date, int date_len) 6675 { 6676 static const LCTYPE dayname[] = { 6677 LOCALE_SDAYNAME7, LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, 6678 LOCALE_SDAYNAME4, LOCALE_SDAYNAME5, LOCALE_SDAYNAME6 6679 }; 6680 static const LCTYPE sdayname[] = { 6681 LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, 6682 LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5, 6683 LOCALE_SABBREVDAYNAME6 6684 }; 6685 static const LCTYPE monthname[] = { 6686 LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4, 6687 LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8, 6688 LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12 6689 }; 6690 static const LCTYPE smonthname[] = { 6691 LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3, 6692 LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6, 6693 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9, 6694 LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 6695 }; 6696 6697 if(flags & ~(LOCALE_NOUSEROVERRIDE|VAR_DATEVALUEONLY)) 6698 FIXME("ignoring flags %x\n", flags); 6699 flags &= LOCALE_NOUSEROVERRIDE; 6700 6701 while(*fmt && date_len) { 6702 int count = 1; 6703 6704 switch(*fmt) { 6705 case 'd': 6706 case 'M': 6707 case 'y': 6708 case 'g': 6709 while(*fmt == *(fmt+count)) 6710 count++; 6711 fmt += count-1; 6712 } 6713 6714 switch(*fmt) { 6715 case 'd': 6716 if(count >= 4) 6717 count = GetLocaleInfoW(lcid, dayname[st->wDayOfWeek] | flags, date, date_len)-1; 6718 else if(count == 3) 6719 count = GetLocaleInfoW(lcid, sdayname[st->wDayOfWeek] | flags, date, date_len)-1; 6720 else 6721 count = output_int_len(st->wDay, count, date, date_len); 6722 break; 6723 case 'M': 6724 if(count >= 4) 6725 count = GetLocaleInfoW(lcid, monthname[st->wMonth-1] | flags, date, date_len)-1; 6726 else if(count == 3) 6727 count = GetLocaleInfoW(lcid, smonthname[st->wMonth-1] | flags, date, date_len)-1; 6728 else 6729 count = output_int_len(st->wMonth, count, date, date_len); 6730 break; 6731 case 'y': 6732 if(count >= 3) 6733 count = output_int_len(st->wYear, 0, date, date_len); 6734 else 6735 count = output_int_len(st->wYear%100, count, date, date_len); 6736 break; 6737 case 'g': 6738 if(count == 2) { 6739 FIXME("Should be using GetCalendarInfo(CAL_SERASTRING), defaulting to 'AD'\n"); 6740 6741 *date++ = 'A'; 6742 date_len--; 6743 if(date_len) 6744 *date = 'D'; 6745 else 6746 count = -1; 6747 break; 6748 } 6749 /* fall through */ 6750 default: 6751 *date = *fmt; 6752 } 6753 6754 if(count < 0) 6755 break; 6756 fmt++; 6757 date += count; 6758 date_len -= count; 6759 } 6760 6761 if(!date_len) 6762 return FALSE; 6763 *date++ = 0; 6764 return TRUE; 6765 } 6766 6767 /****************************************************************************** 6768 * VarBstrFromDate [OLEAUT32.114] 6769 * 6770 * Convert a VT_DATE to a VT_BSTR. 6771 * 6772 * PARAMS 6773 * dateIn [I] Source 6774 * lcid [I] LCID for the conversion 6775 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 6776 * pbstrOut [O] Destination 6777 * 6778 * RETURNS 6779 * Success: S_OK. 6780 * Failure: E_INVALIDARG, if pbstrOut or dateIn is invalid. 6781 * E_OUTOFMEMORY, if memory allocation fails. 6782 */ 6783 HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) 6784 { 6785 SYSTEMTIME st; 6786 DWORD dwFormatFlags = dwFlags & LOCALE_NOUSEROVERRIDE; 6787 WCHAR date[128], fmt_buff[80], *time; 6788 6789 TRACE("(%g,0x%08x,0x%08x,%p)\n", dateIn, lcid, dwFlags, pbstrOut); 6790 6791 if (!pbstrOut || !VariantTimeToSystemTime(dateIn, &st)) 6792 return E_INVALIDARG; 6793 6794 *pbstrOut = NULL; 6795 6796 if (dwFlags & VAR_CALENDAR_THAI) 6797 st.wYear += 553; /* Use the Thai buddhist calendar year */ 6798 else if (dwFlags & (VAR_CALENDAR_HIJRI|VAR_CALENDAR_GREGORIAN)) 6799 FIXME("VAR_CALENDAR_HIJRI/VAR_CALENDAR_GREGORIAN not handled\n"); 6800 6801 if (dwFlags & LOCALE_USE_NLS) 6802 dwFlags &= ~(VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY); 6803 else 6804 { 6805 double whole = dateIn < 0 ? ceil(dateIn) : floor(dateIn); 6806 double partial = dateIn - whole; 6807 6808 if (whole == 0.0) 6809 dwFlags |= VAR_TIMEVALUEONLY; 6810 else if (partial > -1e-12 && partial < 1e-12) 6811 dwFlags |= VAR_DATEVALUEONLY; 6812 } 6813 6814 if (dwFlags & VAR_TIMEVALUEONLY) 6815 date[0] = '\0'; 6816 else 6817 if (!GetLocaleInfoW(lcid, LOCALE_SSHORTDATE, fmt_buff, sizeof(fmt_buff)/sizeof(WCHAR)) || 6818 !get_date_format(lcid, dwFlags, &st, fmt_buff, date, sizeof(date)/sizeof(WCHAR))) 6819 return E_INVALIDARG; 6820 6821 if (!(dwFlags & VAR_DATEVALUEONLY)) 6822 { 6823 time = date + strlenW(date); 6824 if (time != date) 6825 *time++ = ' '; 6826 if (!GetTimeFormatW(lcid, dwFormatFlags, &st, NULL, time, 6827 sizeof(date)/sizeof(WCHAR)-(time-date))) 6828 return E_INVALIDARG; 6829 } 6830 6831 *pbstrOut = SysAllocString(date); 6832 if (*pbstrOut) 6833 TRACE("returning %s\n", debugstr_w(*pbstrOut)); 6834 return *pbstrOut ? S_OK : E_OUTOFMEMORY; 6835 } 6836 6837 /****************************************************************************** 6838 * VarBstrFromBool (OLEAUT32.116) 6839 * 6840 * Convert a VT_BOOL to a VT_BSTR. 6841 * 6842 * PARAMS 6843 * boolIn [I] Source 6844 * lcid [I] LCID for the conversion 6845 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 6846 * pbstrOut [O] Destination 6847 * 6848 * RETURNS 6849 * Success: S_OK. 6850 * Failure: E_INVALIDARG, if pbstrOut is invalid. 6851 * E_OUTOFMEMORY, if memory allocation fails. 6852 * 6853 * NOTES 6854 * If dwFlags includes VARIANT_LOCALBOOL, this function converts to the 6855 * localised text of "True" or "False". To convert a bool into a 6856 * numeric string of "0" or "-1", use VariantChangeTypeTypeEx(). 6857 */ 6858 HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) 6859 { 6860 WCHAR szBuff[64]; 6861 DWORD dwResId = IDS_TRUE; 6862 LANGID langId; 6863 6864 TRACE("%d,0x%08x,0x%08x,%p\n", boolIn, lcid, dwFlags, pbstrOut); 6865 6866 if (!pbstrOut) 6867 return E_INVALIDARG; 6868 6869 /* VAR_BOOLONOFF and VAR_BOOLYESNO are internal flags used 6870 * for variant formatting */ 6871 switch (dwFlags & (VAR_LOCALBOOL|VAR_BOOLONOFF|VAR_BOOLYESNO)) 6872 { 6873 case VAR_BOOLONOFF: 6874 dwResId = IDS_ON; 6875 break; 6876 case VAR_BOOLYESNO: 6877 dwResId = IDS_YES; 6878 break; 6879 case VAR_LOCALBOOL: 6880 break; 6881 default: 6882 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),SORT_DEFAULT); 6883 } 6884 6885 lcid = ConvertDefaultLocale(lcid); 6886 langId = LANGIDFROMLCID(lcid); 6887 if (PRIMARYLANGID(langId) == LANG_NEUTRAL) 6888 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); 6889 6890 if (boolIn == VARIANT_FALSE) 6891 dwResId++; /* Use negative form */ 6892 6893 VarBstrFromBool_GetLocalised: 6894 if (VARIANT_GetLocalisedText(langId, dwResId, szBuff)) 6895 { 6896 *pbstrOut = SysAllocString(szBuff); 6897 return *pbstrOut ? S_OK : E_OUTOFMEMORY; 6898 } 6899 6900 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT)) 6901 { 6902 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); 6903 goto VarBstrFromBool_GetLocalised; 6904 } 6905 6906 /* Should never get here */ 6907 WARN("Failed to load bool text!\n"); 6908 return E_OUTOFMEMORY; 6909 } 6910 6911 /****************************************************************************** 6912 * VarBstrFromI1 (OLEAUT32.229) 6913 * 6914 * Convert a VT_I1 to a VT_BSTR. 6915 * 6916 * PARAMS 6917 * cIn [I] Source 6918 * lcid [I] LCID for the conversion 6919 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 6920 * pbstrOut [O] Destination 6921 * 6922 * RETURNS 6923 * Success: S_OK. 6924 * Failure: E_INVALIDARG, if pbstrOut is invalid. 6925 * E_OUTOFMEMORY, if memory allocation fails. 6926 */ 6927 HRESULT WINAPI VarBstrFromI1(signed char cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) 6928 { 6929 ULONG64 ul64 = cIn; 6930 6931 if (cIn < 0) 6932 { 6933 ul64 = -cIn; 6934 dwFlags |= VAR_NEGATIVE; 6935 } 6936 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut); 6937 } 6938 6939 /****************************************************************************** 6940 * VarBstrFromUI2 (OLEAUT32.230) 6941 * 6942 * Convert a VT_UI2 to a VT_BSTR. 6943 * 6944 * PARAMS 6945 * usIn [I] Source 6946 * lcid [I] LCID for the conversion 6947 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 6948 * pbstrOut [O] Destination 6949 * 6950 * RETURNS 6951 * Success: S_OK. 6952 * Failure: E_INVALIDARG, if pbstrOut is invalid. 6953 * E_OUTOFMEMORY, if memory allocation fails. 6954 */ 6955 HRESULT WINAPI VarBstrFromUI2(USHORT usIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) 6956 { 6957 return VARIANT_BstrFromUInt(usIn, lcid, dwFlags, pbstrOut); 6958 } 6959 6960 /****************************************************************************** 6961 * VarBstrFromUI4 (OLEAUT32.231) 6962 * 6963 * Convert a VT_UI4 to a VT_BSTR. 6964 * 6965 * PARAMS 6966 * ulIn [I] Source 6967 * lcid [I] LCID for the conversion 6968 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 6969 * pbstrOut [O] Destination 6970 * 6971 * RETURNS 6972 * Success: S_OK. 6973 * Failure: E_INVALIDARG, if pbstrOut is invalid. 6974 * E_OUTOFMEMORY, if memory allocation fails. 6975 */ 6976 HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) 6977 { 6978 return VARIANT_BstrFromUInt(ulIn, lcid, dwFlags, pbstrOut); 6979 } 6980 6981 /****************************************************************************** 6982 * VarBstrFromDec (OLEAUT32.232) 6983 * 6984 * Convert a VT_DECIMAL to a VT_BSTR. 6985 * 6986 * PARAMS 6987 * pDecIn [I] Source 6988 * lcid [I] LCID for the conversion 6989 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 6990 * pbstrOut [O] Destination 6991 * 6992 * RETURNS 6993 * Success: S_OK. 6994 * Failure: E_INVALIDARG, if pbstrOut is invalid. 6995 * E_OUTOFMEMORY, if memory allocation fails. 6996 */ 6997 HRESULT WINAPI VarBstrFromDec(DECIMAL* pDecIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) 6998 { 6999 WCHAR buff[256]; 7000 VARIANT_DI temp; 7001 7002 if (!pbstrOut) 7003 return E_INVALIDARG; 7004 7005 VARIANT_DIFromDec(pDecIn, &temp); 7006 VARIANT_DI_tostringW(&temp, buff, 256); 7007 7008 if (dwFlags & LOCALE_USE_NLS) 7009 { 7010 WCHAR numbuff[256]; 7011 7012 /* Format the number for the locale */ 7013 numbuff[0] = '\0'; 7014 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE, 7015 buff, NULL, numbuff, sizeof(numbuff) / sizeof(WCHAR)); 7016 TRACE("created NLS string %s\n", debugstr_w(numbuff)); 7017 *pbstrOut = SysAllocString(numbuff); 7018 } 7019 else 7020 { 7021 *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags); 7022 } 7023 7024 TRACE("returning %s\n", debugstr_w(*pbstrOut)); 7025 return *pbstrOut ? S_OK : E_OUTOFMEMORY; 7026 } 7027 7028 /************************************************************************ 7029 * VarBstrFromI8 (OLEAUT32.370) 7030 * 7031 * Convert a VT_I8 to a VT_BSTR. 7032 * 7033 * PARAMS 7034 * llIn [I] Source 7035 * lcid [I] LCID for the conversion 7036 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 7037 * pbstrOut [O] Destination 7038 * 7039 * RETURNS 7040 * Success: S_OK. 7041 * Failure: E_INVALIDARG, if pbstrOut is invalid. 7042 * E_OUTOFMEMORY, if memory allocation fails. 7043 */ 7044 HRESULT WINAPI VarBstrFromI8(LONG64 llIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) 7045 { 7046 ULONG64 ul64 = llIn; 7047 7048 if (llIn < 0) 7049 { 7050 ul64 = -llIn; 7051 dwFlags |= VAR_NEGATIVE; 7052 } 7053 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut); 7054 } 7055 7056 /************************************************************************ 7057 * VarBstrFromUI8 (OLEAUT32.371) 7058 * 7059 * Convert a VT_UI8 to a VT_BSTR. 7060 * 7061 * PARAMS 7062 * ullIn [I] Source 7063 * lcid [I] LCID for the conversion 7064 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 7065 * pbstrOut [O] Destination 7066 * 7067 * RETURNS 7068 * Success: S_OK. 7069 * Failure: E_INVALIDARG, if pbstrOut is invalid. 7070 * E_OUTOFMEMORY, if memory allocation fails. 7071 */ 7072 HRESULT WINAPI VarBstrFromUI8(ULONG64 ullIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) 7073 { 7074 return VARIANT_BstrFromUInt(ullIn, lcid, dwFlags, pbstrOut); 7075 } 7076 7077 /************************************************************************ 7078 * VarBstrFromDisp (OLEAUT32.115) 7079 * 7080 * Convert a VT_DISPATCH to a BSTR. 7081 * 7082 * PARAMS 7083 * pdispIn [I] Source 7084 * lcid [I] LCID for conversion 7085 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") 7086 * pbstrOut [O] Destination 7087 * 7088 * RETURNS 7089 * Success: S_OK. 7090 * Failure: E_INVALIDARG, if the source value is invalid 7091 * DISP_E_TYPEMISMATCH, if the type cannot be converted 7092 */ 7093 HRESULT WINAPI VarBstrFromDisp(IDispatch* pdispIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) 7094 { 7095 return VARIANT_FromDisp(pdispIn, lcid, pbstrOut, VT_BSTR, dwFlags); 7096 } 7097 7098 /********************************************************************** 7099 * VarBstrCat (OLEAUT32.313) 7100 * 7101 * Concatenate two BSTR values. 7102 * 7103 * PARAMS 7104 * pbstrLeft [I] Source 7105 * pbstrRight [I] Value to concatenate 7106 * pbstrOut [O] Destination 7107 * 7108 * RETURNS 7109 * Success: S_OK. 7110 * Failure: E_INVALIDARG, if pbstrOut is invalid. 7111 * E_OUTOFMEMORY, if memory allocation fails. 7112 */ 7113 HRESULT WINAPI VarBstrCat(BSTR pbstrLeft, BSTR pbstrRight, BSTR *pbstrOut) 7114 { 7115 unsigned int lenLeft, lenRight; 7116 7117 TRACE("%s,%s,%p\n", 7118 debugstr_wn(pbstrLeft, SysStringLen(pbstrLeft)), 7119 debugstr_wn(pbstrRight, SysStringLen(pbstrRight)), pbstrOut); 7120 7121 if (!pbstrOut) 7122 return E_INVALIDARG; 7123 7124 /* use byte length here to properly handle ansi-allocated BSTRs */ 7125 lenLeft = pbstrLeft ? SysStringByteLen(pbstrLeft) : 0; 7126 lenRight = pbstrRight ? SysStringByteLen(pbstrRight) : 0; 7127 7128 *pbstrOut = SysAllocStringByteLen(NULL, lenLeft + lenRight); 7129 if (!*pbstrOut) 7130 return E_OUTOFMEMORY; 7131 7132 (*pbstrOut)[0] = '\0'; 7133 7134 if (pbstrLeft) 7135 memcpy(*pbstrOut, pbstrLeft, lenLeft); 7136 7137 if (pbstrRight) 7138 memcpy((CHAR*)*pbstrOut + lenLeft, pbstrRight, lenRight); 7139 7140 TRACE("%s\n", debugstr_wn(*pbstrOut, SysStringLen(*pbstrOut))); 7141 return S_OK; 7142 } 7143 7144 /********************************************************************** 7145 * VarBstrCmp (OLEAUT32.314) 7146 * 7147 * Compare two BSTR values. 7148 * 7149 * PARAMS 7150 * pbstrLeft [I] Source 7151 * pbstrRight [I] Value to compare 7152 * lcid [I] LCID for the comparison 7153 * dwFlags [I] Flags to pass directly to CompareStringW(). 7154 * 7155 * RETURNS 7156 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pbstrLeft is less 7157 * than, equal to or greater than pbstrRight respectively. 7158 * 7159 * NOTES 7160 * VARCMP_NULL is NOT returned if either string is NULL unlike MSDN 7161 * states. A NULL BSTR pointer is equivalent to an empty string. 7162 * If LCID is equal to 0, a byte by byte comparison is performed. 7163 */ 7164 HRESULT WINAPI VarBstrCmp(BSTR pbstrLeft, BSTR pbstrRight, LCID lcid, DWORD dwFlags) 7165 { 7166 HRESULT hres; 7167 int ret; 7168 7169 TRACE("%s,%s,%d,%08x\n", 7170 debugstr_wn(pbstrLeft, SysStringLen(pbstrLeft)), 7171 debugstr_wn(pbstrRight, SysStringLen(pbstrRight)), lcid, dwFlags); 7172 7173 if (!pbstrLeft || !*pbstrLeft) 7174 { 7175 if (pbstrRight && *pbstrRight) 7176 return VARCMP_LT; 7177 } 7178 else if (!pbstrRight || !*pbstrRight) 7179 return VARCMP_GT; 7180 7181 if (lcid == 0) 7182 { 7183 unsigned int lenLeft = SysStringByteLen(pbstrLeft); 7184 unsigned int lenRight = SysStringByteLen(pbstrRight); 7185 ret = memcmp(pbstrLeft, pbstrRight, min(lenLeft, lenRight)); 7186 if (ret < 0) 7187 return VARCMP_LT; 7188 if (ret > 0) 7189 return VARCMP_GT; 7190 if (lenLeft < lenRight) 7191 return VARCMP_LT; 7192 if (lenLeft > lenRight) 7193 return VARCMP_GT; 7194 return VARCMP_EQ; 7195 } 7196 else 7197 { 7198 unsigned int lenLeft = SysStringLen(pbstrLeft); 7199 unsigned int lenRight = SysStringLen(pbstrRight); 7200 7201 if (lenLeft == 0 || lenRight == 0) 7202 { 7203 if (lenLeft == 0 && lenRight == 0) return VARCMP_EQ; 7204 return lenLeft < lenRight ? VARCMP_LT : VARCMP_GT; 7205 } 7206 7207 hres = CompareStringW(lcid, dwFlags, pbstrLeft, lenLeft, 7208 pbstrRight, lenRight) - CSTR_LESS_THAN; 7209 TRACE("%d\n", hres); 7210 return hres; 7211 } 7212 } 7213 7214 /* 7215 * DATE 7216 */ 7217 7218 /****************************************************************************** 7219 * VarDateFromUI1 (OLEAUT32.88) 7220 * 7221 * Convert a VT_UI1 to a VT_DATE. 7222 * 7223 * PARAMS 7224 * bIn [I] Source 7225 * pdateOut [O] Destination 7226 * 7227 * RETURNS 7228 * S_OK. 7229 */ 7230 HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut) 7231 { 7232 return VarR8FromUI1(bIn, pdateOut); 7233 } 7234 7235 /****************************************************************************** 7236 * VarDateFromI2 (OLEAUT32.89) 7237 * 7238 * Convert a VT_I2 to a VT_DATE. 7239 * 7240 * PARAMS 7241 * sIn [I] Source 7242 * pdateOut [O] Destination 7243 * 7244 * RETURNS 7245 * S_OK. 7246 */ 7247 HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut) 7248 { 7249 return VarR8FromI2(sIn, pdateOut); 7250 } 7251 7252 /****************************************************************************** 7253 * VarDateFromI4 (OLEAUT32.90) 7254 * 7255 * Convert a VT_I4 to a VT_DATE. 7256 * 7257 * PARAMS 7258 * lIn [I] Source 7259 * pdateOut [O] Destination 7260 * 7261 * RETURNS 7262 * S_OK. 7263 */ 7264 HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut) 7265 { 7266 return VarDateFromR8(lIn, pdateOut); 7267 } 7268 7269 /****************************************************************************** 7270 * VarDateFromR4 (OLEAUT32.91) 7271 * 7272 * Convert a VT_R4 to a VT_DATE. 7273 * 7274 * PARAMS 7275 * fltIn [I] Source 7276 * pdateOut [O] Destination 7277 * 7278 * RETURNS 7279 * S_OK. 7280 */ 7281 HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut) 7282 { 7283 return VarR8FromR4(fltIn, pdateOut); 7284 } 7285 7286 /****************************************************************************** 7287 * VarDateFromR8 (OLEAUT32.92) 7288 * 7289 * Convert a VT_R8 to a VT_DATE. 7290 * 7291 * PARAMS 7292 * dblIn [I] Source 7293 * pdateOut [O] Destination 7294 * 7295 * RETURNS 7296 * S_OK. 7297 */ 7298 HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut) 7299 { 7300 if (dblIn <= (DATE_MIN - 1.0) || dblIn >= (DATE_MAX + 1.0)) return DISP_E_OVERFLOW; 7301 *pdateOut = (DATE)dblIn; 7302 return S_OK; 7303 } 7304 7305 /********************************************************************** 7306 * VarDateFromDisp (OLEAUT32.95) 7307 * 7308 * Convert a VT_DISPATCH to a VT_DATE. 7309 * 7310 * PARAMS 7311 * pdispIn [I] Source 7312 * lcid [I] LCID for conversion 7313 * pdateOut [O] Destination 7314 * 7315 * RETURNS 7316 * Success: S_OK. 7317 * Failure: E_INVALIDARG, if the source value is invalid 7318 * DISP_E_OVERFLOW, if the value will not fit in the destination 7319 * DISP_E_TYPEMISMATCH, if the type cannot be converted 7320 */ 7321 HRESULT WINAPI VarDateFromDisp(IDispatch* pdispIn, LCID lcid, DATE* pdateOut) 7322 { 7323 return VARIANT_FromDisp(pdispIn, lcid, pdateOut, VT_DATE, 0); 7324 } 7325 7326 /****************************************************************************** 7327 * VarDateFromBool (OLEAUT32.96) 7328 * 7329 * Convert a VT_BOOL to a VT_DATE. 7330 * 7331 * PARAMS 7332 * boolIn [I] Source 7333 * pdateOut [O] Destination 7334 * 7335 * RETURNS 7336 * S_OK. 7337 */ 7338 HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut) 7339 { 7340 return VarR8FromBool(boolIn, pdateOut); 7341 } 7342 7343 /********************************************************************** 7344 * VarDateFromCy (OLEAUT32.93) 7345 * 7346 * Convert a VT_CY to a VT_DATE. 7347 * 7348 * PARAMS 7349 * lIn [I] Source 7350 * pdateOut [O] Destination 7351 * 7352 * RETURNS 7353 * S_OK. 7354 */ 7355 HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut) 7356 { 7357 return VarR8FromCy(cyIn, pdateOut); 7358 } 7359 7360 /* Date string parsing */ 7361 #define DP_TIMESEP 0x01 /* Time separator ( _must_ remain 0x1, used as a bitmask) */ 7362 #define DP_DATESEP 0x02 /* Date separator */ 7363 #define DP_MONTH 0x04 /* Month name */ 7364 #define DP_AM 0x08 /* AM */ 7365 #define DP_PM 0x10 /* PM */ 7366 7367 typedef struct tagDATEPARSE 7368 { 7369 DWORD dwCount; /* Number of fields found so far (maximum 6) */ 7370 DWORD dwParseFlags; /* Global parse flags (DP_ Flags above) */ 7371 DWORD dwFlags[6]; /* Flags for each field */ 7372 DWORD dwValues[6]; /* Value of each field */ 7373 } DATEPARSE; 7374 7375 #define TIMEFLAG(i) ((dp.dwFlags[i] & DP_TIMESEP) << i) 7376 7377 #define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0))) 7378 7379 /* Determine if a day is valid in a given month of a given year */ 7380 static BOOL VARIANT_IsValidMonthDay(DWORD day, DWORD month, DWORD year) 7381 { 7382 static const BYTE days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 7383 7384 if (day && month && month < 13) 7385 { 7386 if (day <= days[month] || (month == 2 && day == 29 && IsLeapYear(year))) 7387 return TRUE; 7388 } 7389 return FALSE; 7390 } 7391 7392 /* Possible orders for 3 numbers making up a date */ 7393 #define ORDER_MDY 0x01 7394 #define ORDER_YMD 0x02 7395 #define ORDER_YDM 0x04 7396 #define ORDER_DMY 0x08 7397 #define ORDER_MYD 0x10 /* Synthetic order, used only for funky 2 digit dates */ 7398 7399 /* Determine a date for a particular locale, from 3 numbers */ 7400 static inline HRESULT VARIANT_MakeDate(DATEPARSE *dp, DWORD iDate, 7401 DWORD offset, SYSTEMTIME *st) 7402 { 7403 DWORD dwAllOrders, dwTry, dwCount = 0, v1, v2, v3; 7404 7405 if (!dp->dwCount) 7406 { 7407 v1 = 30; /* Default to (Variant) 0 date part */ 7408 v2 = 12; 7409 v3 = 1899; 7410 goto VARIANT_MakeDate_OK; 7411 } 7412 7413 v1 = dp->dwValues[offset + 0]; 7414 v2 = dp->dwValues[offset + 1]; 7415 if (dp->dwCount == 2) 7416 { 7417 SYSTEMTIME current; 7418 GetSystemTime(¤t); 7419 v3 = current.wYear; 7420 } 7421 else 7422 v3 = dp->dwValues[offset + 2]; 7423 7424 TRACE("(%d,%d,%d,%d,%d)\n", v1, v2, v3, iDate, offset); 7425 7426 /* If one number must be a month (Because a month name was given), then only 7427 * consider orders with the month in that position. 7428 * If we took the current year as 'v3', then only allow a year in that position. 7429 */ 7430 if (dp->dwFlags[offset + 0] & DP_MONTH) 7431 { 7432 dwAllOrders = ORDER_MDY; 7433 } 7434 else if (dp->dwFlags[offset + 1] & DP_MONTH) 7435 { 7436 dwAllOrders = ORDER_DMY; 7437 if (dp->dwCount > 2) 7438 dwAllOrders |= ORDER_YMD; 7439 } 7440 else if (dp->dwCount > 2 && dp->dwFlags[offset + 2] & DP_MONTH) 7441 { 7442 dwAllOrders = ORDER_YDM; 7443 } 7444 else 7445 { 7446 dwAllOrders = ORDER_MDY|ORDER_DMY; 7447 if (dp->dwCount > 2) 7448 dwAllOrders |= (ORDER_YMD|ORDER_YDM); 7449 } 7450 7451 VARIANT_MakeDate_Start: 7452 TRACE("dwAllOrders is 0x%08x\n", dwAllOrders); 7453 7454 while (dwAllOrders) 7455 { 7456 DWORD dwTemp; 7457 7458 if (dwCount == 0) 7459 { 7460 /* First: Try the order given by iDate */ 7461 switch (iDate) 7462 { 7463 case 0: dwTry = dwAllOrders & ORDER_MDY; break; 7464 case 1: dwTry = dwAllOrders & ORDER_DMY; break; 7465 default: dwTry = dwAllOrders & ORDER_YMD; break; 7466 } 7467 } 7468 else if (dwCount == 1) 7469 { 7470 /* Second: Try all the orders compatible with iDate */ 7471 switch (iDate) 7472 { 7473 case 0: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break; 7474 case 1: dwTry = dwAllOrders & ~(ORDER_MDY|ORDER_YDM|ORDER_MYD); break; 7475 default: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break; 7476 } 7477 } 7478 else 7479 { 7480 /* Finally: Try any remaining orders */ 7481 dwTry = dwAllOrders; 7482 } 7483 7484 TRACE("Attempt %d, dwTry is 0x%08x\n", dwCount, dwTry); 7485 7486 dwCount++; 7487 if (!dwTry) 7488 continue; 7489 7490 #define DATE_SWAP(x,y) do { dwTemp = x; x = y; y = dwTemp; } while (0) 7491 7492 if (dwTry & ORDER_MDY) 7493 { 7494 if (VARIANT_IsValidMonthDay(v2,v1,v3)) 7495 { 7496 DATE_SWAP(v1,v2); 7497 goto VARIANT_MakeDate_OK; 7498 } 7499 dwAllOrders &= ~ORDER_MDY; 7500 } 7501 if (dwTry & ORDER_YMD) 7502 { 7503 if (VARIANT_IsValidMonthDay(v3,v2,v1)) 7504 { 7505 DATE_SWAP(v1,v3); 7506 goto VARIANT_MakeDate_OK; 7507 } 7508 dwAllOrders &= ~ORDER_YMD; 7509 } 7510 if (dwTry & ORDER_YDM) 7511 { 7512 if (VARIANT_IsValidMonthDay(v2,v3,v1)) 7513 { 7514 DATE_SWAP(v1,v2); 7515 DATE_SWAP(v2,v3); 7516 goto VARIANT_MakeDate_OK; 7517 } 7518 dwAllOrders &= ~ORDER_YDM; 7519 } 7520 if (dwTry & ORDER_DMY) 7521 { 7522 if (VARIANT_IsValidMonthDay(v1,v2,v3)) 7523 goto VARIANT_MakeDate_OK; 7524 dwAllOrders &= ~ORDER_DMY; 7525 } 7526 if (dwTry & ORDER_MYD) 7527 { 7528 /* Only occurs if we are trying a 2 year date as M/Y not D/M */ 7529 if (VARIANT_IsValidMonthDay(v3,v1,v2)) 7530 { 7531 DATE_SWAP(v1,v3); 7532 DATE_SWAP(v2,v3); 7533 goto VARIANT_MakeDate_OK; 7534 } 7535 dwAllOrders &= ~ORDER_MYD; 7536 } 7537 } 7538 7539 if (dp->dwCount == 2) 7540 { 7541 /* We couldn't make a date as D/M or M/D, so try M/Y or Y/M */ 7542 v3 = 1; /* 1st of the month */ 7543 dwAllOrders = ORDER_YMD|ORDER_MYD; 7544 dp->dwCount = 0; /* Don't return to this code path again */ 7545 dwCount = 0; 7546 goto VARIANT_MakeDate_Start; 7547 } 7548 7549 /* No valid dates were able to be constructed */ 7550 return DISP_E_TYPEMISMATCH; 7551 7552 VARIANT_MakeDate_OK: 7553 7554 /* Check that the time part is ok */ 7555 if (st->wHour > 23 || st->wMinute > 59 || st->wSecond > 59) 7556 return DISP_E_TYPEMISMATCH; 7557 7558 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond); 7559 if (st->wHour < 12 && (dp->dwParseFlags & DP_PM)) 7560 st->wHour += 12; 7561 else if (st->wHour == 12 && (dp->dwParseFlags & DP_AM)) 7562 st->wHour = 0; 7563 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond); 7564 7565 st->wDay = v1; 7566 st->wMonth = v2; 7567 /* FIXME: For 2 digit dates, I'm not sure if 30 is hard coded or not. It may 7568 * be retrieved from: 7569 * HKCU\Control Panel\International\Calendars\TwoDigitYearMax 7570 * But Wine doesn't have/use that key as at the time of writing. 7571 */ 7572 st->wYear = v3 < 30 ? 2000 + v3 : v3 < 100 ? 1900 + v3 : v3; 7573 TRACE("Returning date %d/%d/%d\n", v1, v2, st->wYear); 7574 return S_OK; 7575 } 7576 7577 /****************************************************************************** 7578 * VarDateFromStr [OLEAUT32.94] 7579 * 7580 * Convert a VT_BSTR to at VT_DATE. 7581 * 7582 * PARAMS 7583 * strIn [I] String to convert 7584 * lcid [I] Locale identifier for the conversion 7585 * dwFlags [I] Flags affecting the conversion (VAR_ flags from "oleauto.h") 7586 * pdateOut [O] Destination for the converted value 7587 * 7588 * RETURNS 7589 * Success: S_OK. pdateOut contains the converted value. 7590 * FAILURE: An HRESULT error code indicating the problem. 7591 * 7592 * NOTES 7593 * Any date format that can be created using the date formats from lcid 7594 * (Either from kernel Nls functions, variant conversion or formatting) is a 7595 * valid input to this function. In addition, a few more esoteric formats are 7596 * also supported for compatibility with the native version. The date is 7597 * interpreted according to the date settings in the control panel, unless 7598 * the date is invalid in that format, in which the most compatible format 7599 * that produces a valid date will be used. 7600 */ 7601 HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut) 7602 { 7603 static const USHORT ParseDateTokens[] = 7604 { 7605 LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4, 7606 LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8, 7607 LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12, 7608 LOCALE_SMONTHNAME13, 7609 LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3, 7610 LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6, 7611 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9, 7612 LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12, 7613 LOCALE_SABBREVMONTHNAME13, 7614 LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4, 7615 LOCALE_SDAYNAME5, LOCALE_SDAYNAME6, LOCALE_SDAYNAME7, 7616 LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, 7617 LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6, 7618 LOCALE_SABBREVDAYNAME7, 7619 LOCALE_S1159, LOCALE_S2359, 7620 LOCALE_SDATE 7621 }; 7622 static const BYTE ParseDateMonths[] = 7623 { 7624 1,2,3,4,5,6,7,8,9,10,11,12,13, 7625 1,2,3,4,5,6,7,8,9,10,11,12,13 7626 }; 7627 unsigned int i; 7628 BSTR tokens[sizeof(ParseDateTokens)/sizeof(ParseDateTokens[0])]; 7629 DATEPARSE dp; 7630 DWORD dwDateSeps = 0, iDate = 0; 7631 HRESULT hRet = S_OK; 7632 7633 if ((dwFlags & (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY)) == 7634 (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY)) 7635 return E_INVALIDARG; 7636 7637 if (!strIn) 7638 return DISP_E_TYPEMISMATCH; 7639 7640 *pdateOut = 0.0; 7641 7642 TRACE("(%s,0x%08x,0x%08x,%p)\n", debugstr_w(strIn), lcid, dwFlags, pdateOut); 7643 7644 memset(&dp, 0, sizeof(dp)); 7645 7646 GetLocaleInfoW(lcid, LOCALE_IDATE|LOCALE_RETURN_NUMBER|(dwFlags & LOCALE_NOUSEROVERRIDE), 7647 (LPWSTR)&iDate, sizeof(iDate)/sizeof(WCHAR)); 7648 TRACE("iDate is %d\n", iDate); 7649 7650 /* Get the month/day/am/pm tokens for this locale */ 7651 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++) 7652 { 7653 WCHAR buff[128]; 7654 LCTYPE lctype = ParseDateTokens[i] | (dwFlags & LOCALE_NOUSEROVERRIDE); 7655 7656 /* FIXME: Alternate calendars - should use GetCalendarInfo() and/or 7657 * GetAltMonthNames(). We should really cache these strings too. 7658 */ 7659 buff[0] = '\0'; 7660 GetLocaleInfoW(lcid, lctype, buff, sizeof(buff)/sizeof(WCHAR)); 7661 tokens[i] = SysAllocString(buff); 7662 TRACE("token %d is %s\n", i, debugstr_w(tokens[i])); 7663 } 7664 7665 /* Parse the string into our structure */ 7666 while (*strIn) 7667 { 7668 if (isdigitW(*strIn)) 7669 { 7670 if (dp.dwCount >= 6) 7671 { 7672 hRet = DISP_E_TYPEMISMATCH; 7673 break; 7674 } 7675 dp.dwValues[dp.dwCount] = strtoulW(strIn, &strIn, 10); 7676 dp.dwCount++; 7677 strIn--; 7678 } 7679 else if (isalphaW(*strIn)) 7680 { 7681 BOOL bFound = FALSE; 7682 7683 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++) 7684 { 7685 DWORD dwLen = strlenW(tokens[i]); 7686 if (dwLen && !strncmpiW(strIn, tokens[i], dwLen)) 7687 { 7688 if (i <= 25) 7689 { 7690 if (dp.dwCount >= 6) 7691 hRet = DISP_E_TYPEMISMATCH; 7692 else 7693 { 7694 dp.dwValues[dp.dwCount] = ParseDateMonths[i]; 7695 dp.dwFlags[dp.dwCount] |= (DP_MONTH|DP_DATESEP); 7696 dp.dwCount++; 7697 } 7698 } 7699 else if (i > 39 && i < 42) 7700 { 7701 if (!dp.dwCount || dp.dwParseFlags & (DP_AM|DP_PM)) 7702 hRet = DISP_E_TYPEMISMATCH; 7703 else 7704 { 7705 dp.dwFlags[dp.dwCount - 1] |= (i == 40 ? DP_AM : DP_PM); 7706 dp.dwParseFlags |= (i == 40 ? DP_AM : DP_PM); 7707 } 7708 } 7709 strIn += (dwLen - 1); 7710 bFound = TRUE; 7711 break; 7712 } 7713 } 7714 7715 if (!bFound) 7716 { 7717 if ((*strIn == 'a' || *strIn == 'A' || *strIn == 'p' || *strIn == 'P') && 7718 (dp.dwCount && !(dp.dwParseFlags & (DP_AM|DP_PM)))) 7719 { 7720 /* Special case - 'a' and 'p' are recognised as short for am/pm */ 7721 if (*strIn == 'a' || *strIn == 'A') 7722 { 7723 dp.dwFlags[dp.dwCount - 1] |= DP_AM; 7724 dp.dwParseFlags |= DP_AM; 7725 } 7726 else 7727 { 7728 dp.dwFlags[dp.dwCount - 1] |= DP_PM; 7729 dp.dwParseFlags |= DP_PM; 7730 } 7731 strIn++; 7732 } 7733 else 7734 { 7735 TRACE("No matching token for %s\n", debugstr_w(strIn)); 7736 hRet = DISP_E_TYPEMISMATCH; 7737 break; 7738 } 7739 } 7740 } 7741 else if (*strIn == ':' || *strIn == '.') 7742 { 7743 if (!dp.dwCount || !strIn[1]) 7744 hRet = DISP_E_TYPEMISMATCH; 7745 else 7746 if (tokens[42][0] == *strIn) 7747 { 7748 dwDateSeps++; 7749 if (dwDateSeps > 2) 7750 hRet = DISP_E_TYPEMISMATCH; 7751 else 7752 dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP; 7753 } 7754 else 7755 dp.dwFlags[dp.dwCount - 1] |= DP_TIMESEP; 7756 } 7757 else if (*strIn == '-' || *strIn == '/') 7758 { 7759 dwDateSeps++; 7760 if (dwDateSeps > 2 || !dp.dwCount || !strIn[1]) 7761 hRet = DISP_E_TYPEMISMATCH; 7762 else 7763 dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP; 7764 } 7765 else if (*strIn == ',' || isspaceW(*strIn)) 7766 { 7767 if (*strIn == ',' && !strIn[1]) 7768 hRet = DISP_E_TYPEMISMATCH; 7769 } 7770 else 7771 { 7772 hRet = DISP_E_TYPEMISMATCH; 7773 } 7774 strIn++; 7775 } 7776 7777 if (!dp.dwCount || dp.dwCount > 6 || 7778 (dp.dwCount == 1 && !(dp.dwParseFlags & (DP_AM|DP_PM)))) 7779 hRet = DISP_E_TYPEMISMATCH; 7780 7781 if (SUCCEEDED(hRet)) 7782 { 7783 SYSTEMTIME st; 7784 DWORD dwOffset = 0; /* Start of date fields in dp.dwValues */ 7785 7786 st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0; 7787 7788 /* Figure out which numbers correspond to which fields. 7789 * 7790 * This switch statement works based on the fact that native interprets any 7791 * fields that are not joined with a time separator ('.' or ':') as date 7792 * fields. Thus we construct a value from 0-32 where each set bit indicates 7793 * a time field. This encapsulates the hundreds of permutations of 2-6 fields. 7794 * For valid permutations, we set dwOffset to point to the first date field 7795 * and shorten dp.dwCount by the number of time fields found. The real 7796 * magic here occurs in VARIANT_MakeDate() above, where we determine what 7797 * each date number must represent in the context of iDate. 7798 */ 7799 TRACE("0x%08x\n", TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4)); 7800 7801 switch (TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4)) 7802 { 7803 case 0x1: /* TT TTDD TTDDD */ 7804 if (dp.dwCount > 3 && 7805 ((dp.dwFlags[2] & (DP_AM|DP_PM)) || (dp.dwFlags[3] & (DP_AM|DP_PM)) || 7806 (dp.dwFlags[4] & (DP_AM|DP_PM)))) 7807 hRet = DISP_E_TYPEMISMATCH; 7808 else if (dp.dwCount != 2 && dp.dwCount != 4 && dp.dwCount != 5) 7809 hRet = DISP_E_TYPEMISMATCH; 7810 st.wHour = dp.dwValues[0]; 7811 st.wMinute = dp.dwValues[1]; 7812 dp.dwCount -= 2; 7813 dwOffset = 2; 7814 break; 7815 7816 case 0x3: /* TTT TTTDD TTTDDD */ 7817 if (dp.dwCount > 4 && 7818 ((dp.dwFlags[3] & (DP_AM|DP_PM)) || (dp.dwFlags[4] & (DP_AM|DP_PM)) || 7819 (dp.dwFlags[5] & (DP_AM|DP_PM)))) 7820 hRet = DISP_E_TYPEMISMATCH; 7821 else if (dp.dwCount != 3 && dp.dwCount != 5 && dp.dwCount != 6) 7822 hRet = DISP_E_TYPEMISMATCH; 7823 st.wHour = dp.dwValues[0]; 7824 st.wMinute = dp.dwValues[1]; 7825 st.wSecond = dp.dwValues[2]; 7826 dwOffset = 3; 7827 dp.dwCount -= 3; 7828 break; 7829 7830 case 0x4: /* DDTT */ 7831 if (dp.dwCount != 4 || 7832 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM))) 7833 hRet = DISP_E_TYPEMISMATCH; 7834 7835 st.wHour = dp.dwValues[2]; 7836 st.wMinute = dp.dwValues[3]; 7837 dp.dwCount -= 2; 7838 break; 7839 7840 case 0x0: /* T DD DDD TDDD TDDD */ 7841 if (dp.dwCount == 1 && (dp.dwParseFlags & (DP_AM|DP_PM))) 7842 { 7843 st.wHour = dp.dwValues[0]; /* T */ 7844 dp.dwCount = 0; 7845 break; 7846 } 7847 else if (dp.dwCount > 4 || (dp.dwCount < 3 && dp.dwParseFlags & (DP_AM|DP_PM))) 7848 { 7849 hRet = DISP_E_TYPEMISMATCH; 7850 } 7851 else if (dp.dwCount == 3) 7852 { 7853 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDD */ 7854 { 7855 dp.dwCount = 2; 7856 st.wHour = dp.dwValues[0]; 7857 dwOffset = 1; 7858 break; 7859 } 7860 if (dp.dwFlags[2] & (DP_AM|DP_PM)) /* DDT */ 7861 { 7862 dp.dwCount = 2; 7863 st.wHour = dp.dwValues[2]; 7864 break; 7865 } 7866 else if (dp.dwParseFlags & (DP_AM|DP_PM)) 7867 hRet = DISP_E_TYPEMISMATCH; 7868 } 7869 else if (dp.dwCount == 4) 7870 { 7871 dp.dwCount = 3; 7872 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDDD */ 7873 { 7874 st.wHour = dp.dwValues[0]; 7875 dwOffset = 1; 7876 } 7877 else if (dp.dwFlags[3] & (DP_AM|DP_PM)) /* DDDT */ 7878 { 7879 st.wHour = dp.dwValues[3]; 7880 } 7881 else 7882 hRet = DISP_E_TYPEMISMATCH; 7883 break; 7884 } 7885 /* .. fall through .. */ 7886 7887 case 0x8: /* DDDTT */ 7888 if ((dp.dwCount == 2 && (dp.dwParseFlags & (DP_AM|DP_PM))) || 7889 (dp.dwCount == 5 && ((dp.dwFlags[0] & (DP_AM|DP_PM)) || 7890 (dp.dwFlags[1] & (DP_AM|DP_PM)) || (dp.dwFlags[2] & (DP_AM|DP_PM)))) || 7891 dp.dwCount == 4 || dp.dwCount == 6) 7892 hRet = DISP_E_TYPEMISMATCH; 7893 st.wHour = dp.dwValues[3]; 7894 st.wMinute = dp.dwValues[4]; 7895 if (dp.dwCount == 5) 7896 dp.dwCount -= 2; 7897 break; 7898 7899 case 0xC: /* DDTTT */ 7900 if (dp.dwCount != 5 || 7901 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM))) 7902 hRet = DISP_E_TYPEMISMATCH; 7903 st.wHour = dp.dwValues[2]; 7904 st.wMinute = dp.dwValues[3]; 7905 st.wSecond = dp.dwValues[4]; 7906 dp.dwCount -= 3; 7907 break; 7908 7909 case 0x18: /* DDDTTT */ 7910 if ((dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)) || 7911 (dp.dwFlags[2] & (DP_AM|DP_PM))) 7912 hRet = DISP_E_TYPEMISMATCH; 7913 st.wHour = dp.dwValues[3]; 7914 st.wMinute = dp.dwValues[4]; 7915 st.wSecond = dp.dwValues[5]; 7916 dp.dwCount -= 3; 7917 break; 7918 7919 default: 7920 hRet = DISP_E_TYPEMISMATCH; 7921 break; 7922 } 7923 7924 if (SUCCEEDED(hRet)) 7925 { 7926 hRet = VARIANT_MakeDate(&dp, iDate, dwOffset, &st); 7927 7928 if (dwFlags & VAR_TIMEVALUEONLY) 7929 { 7930 st.wYear = 1899; 7931 st.wMonth = 12; 7932 st.wDay = 30; 7933 } 7934 else if (dwFlags & VAR_DATEVALUEONLY) 7935 st.wHour = st.wMinute = st.wSecond = 0; 7936 7937 /* Finally, convert the value to a VT_DATE */ 7938 if (SUCCEEDED(hRet)) 7939 hRet = SystemTimeToVariantTime(&st, pdateOut) ? S_OK : DISP_E_TYPEMISMATCH; 7940 } 7941 } 7942 7943 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++) 7944 SysFreeString(tokens[i]); 7945 return hRet; 7946 } 7947 7948 /****************************************************************************** 7949 * VarDateFromI1 (OLEAUT32.221) 7950 * 7951 * Convert a VT_I1 to a VT_DATE. 7952 * 7953 * PARAMS 7954 * cIn [I] Source 7955 * pdateOut [O] Destination 7956 * 7957 * RETURNS 7958 * S_OK. 7959 */ 7960 HRESULT WINAPI VarDateFromI1(signed char cIn, DATE* pdateOut) 7961 { 7962 return VarR8FromI1(cIn, pdateOut); 7963 } 7964 7965 /****************************************************************************** 7966 * VarDateFromUI2 (OLEAUT32.222) 7967 * 7968 * Convert a VT_UI2 to a VT_DATE. 7969 * 7970 * PARAMS 7971 * uiIn [I] Source 7972 * pdateOut [O] Destination 7973 * 7974 * RETURNS 7975 * S_OK. 7976 */ 7977 HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut) 7978 { 7979 return VarR8FromUI2(uiIn, pdateOut); 7980 } 7981 7982 /****************************************************************************** 7983 * VarDateFromUI4 (OLEAUT32.223) 7984 * 7985 * Convert a VT_UI4 to a VT_DATE. 7986 * 7987 * PARAMS 7988 * ulIn [I] Source 7989 * pdateOut [O] Destination 7990 * 7991 * RETURNS 7992 * S_OK. 7993 */ 7994 HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut) 7995 { 7996 return VarDateFromR8(ulIn, pdateOut); 7997 } 7998 7999 /********************************************************************** 8000 * VarDateFromDec (OLEAUT32.224) 8001 * 8002 * Convert a VT_DECIMAL to a VT_DATE. 8003 * 8004 * PARAMS 8005 * pdecIn [I] Source 8006 * pdateOut [O] Destination 8007 * 8008 * RETURNS 8009 * S_OK. 8010 */ 8011 HRESULT WINAPI VarDateFromDec(DECIMAL *pdecIn, DATE* pdateOut) 8012 { 8013 return VarR8FromDec(pdecIn, pdateOut); 8014 } 8015 8016 /****************************************************************************** 8017 * VarDateFromI8 (OLEAUT32.364) 8018 * 8019 * Convert a VT_I8 to a VT_DATE. 8020 * 8021 * PARAMS 8022 * llIn [I] Source 8023 * pdateOut [O] Destination 8024 * 8025 * RETURNS 8026 * Success: S_OK. 8027 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 8028 */ 8029 HRESULT WINAPI VarDateFromI8(LONG64 llIn, DATE* pdateOut) 8030 { 8031 if (llIn < DATE_MIN || llIn > DATE_MAX) return DISP_E_OVERFLOW; 8032 *pdateOut = (DATE)llIn; 8033 return S_OK; 8034 } 8035 8036 /****************************************************************************** 8037 * VarDateFromUI8 (OLEAUT32.365) 8038 * 8039 * Convert a VT_UI8 to a VT_DATE. 8040 * 8041 * PARAMS 8042 * ullIn [I] Source 8043 * pdateOut [O] Destination 8044 * 8045 * RETURNS 8046 * Success: S_OK. 8047 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination 8048 */ 8049 HRESULT WINAPI VarDateFromUI8(ULONG64 ullIn, DATE* pdateOut) 8050 { 8051 if (ullIn > DATE_MAX) return DISP_E_OVERFLOW; 8052 *pdateOut = (DATE)ullIn; 8053 return S_OK; 8054 } 8055