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