1 /* 2 * PropVariant implementation 3 * 4 * Copyright 2008 James Hawkins for CodeWeavers 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 #include "config.h" 22 #include "wine/port.h" 23 24 #include <stdarg.h> 25 #include <stdio.h> 26 #include <stdlib.h> 27 28 #define NONAMELESSUNION 29 30 #include "windef.h" 31 #include "winbase.h" 32 #include "winerror.h" 33 #include "winreg.h" 34 #include "winuser.h" 35 #include "shlobj.h" 36 #include "propvarutil.h" 37 38 #include "wine/debug.h" 39 #include "wine/unicode.h" 40 41 WINE_DEFAULT_DEBUG_CHANNEL(propsys); 42 43 static HRESULT PROPVAR_ConvertFILETIME(const FILETIME *ft, PROPVARIANT *ppropvarDest, VARTYPE vt) 44 { 45 SYSTEMTIME time; 46 47 FileTimeToSystemTime(ft, &time); 48 49 switch (vt) 50 { 51 case VT_LPSTR: 52 ppropvarDest->u.pszVal = HeapAlloc(GetProcessHeap(), 0, 64); 53 if (!ppropvarDest->u.pszVal) 54 return E_OUTOFMEMORY; 55 56 sprintf( ppropvarDest->u.pszVal, "%04d/%02d/%02d:%02d:%02d:%02d.%03d", 57 time.wYear, time.wMonth, time.wDay, 58 time.wHour, time.wMinute, time.wSecond, 59 time.wMilliseconds ); 60 61 return S_OK; 62 63 default: 64 FIXME("Unhandled target type: %d\n", vt); 65 } 66 67 return E_FAIL; 68 } 69 70 static HRESULT PROPVAR_ConvertNumber(REFPROPVARIANT pv, int dest_bits, 71 BOOL dest_signed, LONGLONG *res) 72 { 73 BOOL src_signed; 74 75 switch (pv->vt) 76 { 77 case VT_I1: 78 src_signed = TRUE; 79 *res = pv->u.cVal; 80 break; 81 case VT_UI1: 82 src_signed = FALSE; 83 *res = pv->u.bVal; 84 break; 85 case VT_I2: 86 src_signed = TRUE; 87 *res = pv->u.iVal; 88 break; 89 case VT_UI2: 90 src_signed = FALSE; 91 *res = pv->u.uiVal; 92 break; 93 case VT_I4: 94 src_signed = TRUE; 95 *res = pv->u.lVal; 96 break; 97 case VT_UI4: 98 src_signed = FALSE; 99 *res = pv->u.ulVal; 100 break; 101 case VT_I8: 102 src_signed = TRUE; 103 *res = pv->u.hVal.QuadPart; 104 break; 105 case VT_UI8: 106 src_signed = FALSE; 107 *res = pv->u.uhVal.QuadPart; 108 break; 109 case VT_EMPTY: 110 src_signed = FALSE; 111 *res = 0; 112 break; 113 case VT_LPSTR: 114 { 115 char *end; 116 *res = _strtoi64(pv->u.pszVal, &end, 0); 117 if (pv->u.pszVal == end) 118 return DISP_E_TYPEMISMATCH; 119 src_signed = *res < 0; 120 break; 121 } 122 case VT_LPWSTR: 123 case VT_BSTR: 124 { 125 WCHAR *end; 126 *res = strtolW(pv->u.pwszVal, &end, 0); 127 if (pv->u.pwszVal == end) 128 return DISP_E_TYPEMISMATCH; 129 src_signed = *res < 0; 130 break; 131 } 132 default: 133 FIXME("unhandled vt %d\n", pv->vt); 134 return E_NOTIMPL; 135 } 136 137 if (*res < 0 && src_signed != dest_signed) 138 return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); 139 140 if (dest_bits < 64) 141 { 142 if (dest_signed) 143 { 144 if (*res >= ((LONGLONG)1 << (dest_bits-1)) || 145 *res < ((LONGLONG)-1 << (dest_bits-1))) 146 return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); 147 } 148 else 149 { 150 if ((ULONGLONG)(*res) >= ((ULONGLONG)1 << dest_bits)) 151 return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); 152 } 153 } 154 155 return S_OK; 156 } 157 158 HRESULT WINAPI PropVariantToInt16(REFPROPVARIANT propvarIn, SHORT *ret) 159 { 160 LONGLONG res; 161 HRESULT hr; 162 163 TRACE("%p,%p\n", propvarIn, ret); 164 165 hr = PROPVAR_ConvertNumber(propvarIn, 16, TRUE, &res); 166 if (SUCCEEDED(hr)) *ret = (SHORT)res; 167 return hr; 168 } 169 170 HRESULT WINAPI PropVariantToInt32(REFPROPVARIANT propvarIn, LONG *ret) 171 { 172 LONGLONG res; 173 HRESULT hr; 174 175 TRACE("%p,%p\n", propvarIn, ret); 176 177 hr = PROPVAR_ConvertNumber(propvarIn, 32, TRUE, &res); 178 if (SUCCEEDED(hr)) *ret = (LONG)res; 179 return hr; 180 } 181 182 HRESULT WINAPI PropVariantToInt64(REFPROPVARIANT propvarIn, LONGLONG *ret) 183 { 184 LONGLONG res; 185 HRESULT hr; 186 187 TRACE("%p,%p\n", propvarIn, ret); 188 189 hr = PROPVAR_ConvertNumber(propvarIn, 64, TRUE, &res); 190 if (SUCCEEDED(hr)) *ret = (LONGLONG)res; 191 return hr; 192 } 193 194 HRESULT WINAPI PropVariantToUInt16(REFPROPVARIANT propvarIn, USHORT *ret) 195 { 196 LONGLONG res; 197 HRESULT hr; 198 199 TRACE("%p,%p\n", propvarIn, ret); 200 201 hr = PROPVAR_ConvertNumber(propvarIn, 16, FALSE, &res); 202 if (SUCCEEDED(hr)) *ret = (USHORT)res; 203 return hr; 204 } 205 206 HRESULT WINAPI PropVariantToUInt32(REFPROPVARIANT propvarIn, ULONG *ret) 207 { 208 LONGLONG res; 209 HRESULT hr; 210 211 TRACE("%p,%p\n", propvarIn, ret); 212 213 hr = PROPVAR_ConvertNumber(propvarIn, 32, FALSE, &res); 214 if (SUCCEEDED(hr)) *ret = (ULONG)res; 215 return hr; 216 } 217 218 HRESULT WINAPI PropVariantToUInt64(REFPROPVARIANT propvarIn, ULONGLONG *ret) 219 { 220 LONGLONG res; 221 HRESULT hr; 222 223 TRACE("%p,%p\n", propvarIn, ret); 224 225 hr = PROPVAR_ConvertNumber(propvarIn, 64, FALSE, &res); 226 if (SUCCEEDED(hr)) *ret = (ULONGLONG)res; 227 return hr; 228 } 229 230 HRESULT WINAPI PropVariantToBoolean(REFPROPVARIANT propvarIn, BOOL *ret) 231 { 232 static const WCHAR trueW[] = {'t','r','u','e',0}; 233 static const WCHAR falseW[] = {'f','a','l','s','e',0}; 234 static const WCHAR true2W[] = {'#','T','R','U','E','#',0}; 235 static const WCHAR false2W[] = {'#','F','A','L','S','E','#',0}; 236 LONGLONG res; 237 HRESULT hr; 238 239 TRACE("%p,%p\n", propvarIn, ret); 240 241 *ret = FALSE; 242 243 switch (propvarIn->vt) 244 { 245 case VT_BOOL: 246 *ret = propvarIn->u.boolVal == VARIANT_TRUE; 247 return S_OK; 248 249 case VT_LPWSTR: 250 case VT_BSTR: 251 if (!propvarIn->u.pwszVal) 252 return DISP_E_TYPEMISMATCH; 253 254 if (!lstrcmpiW(propvarIn->u.pwszVal, trueW) || !lstrcmpW(propvarIn->u.pwszVal, true2W)) 255 { 256 *ret = TRUE; 257 return S_OK; 258 } 259 260 if (!lstrcmpiW(propvarIn->u.pwszVal, falseW) || !lstrcmpW(propvarIn->u.pwszVal, false2W)) 261 { 262 *ret = FALSE; 263 return S_OK; 264 } 265 break; 266 267 case VT_LPSTR: 268 if (!propvarIn->u.pszVal) 269 return DISP_E_TYPEMISMATCH; 270 271 if (!lstrcmpiA(propvarIn->u.pszVal, "true") || !lstrcmpA(propvarIn->u.pszVal, "#TRUE#")) 272 { 273 *ret = TRUE; 274 return S_OK; 275 } 276 277 if (!lstrcmpiA(propvarIn->u.pszVal, "false") || !lstrcmpA(propvarIn->u.pszVal, "#FALSE#")) 278 { 279 *ret = FALSE; 280 return S_OK; 281 } 282 break; 283 } 284 285 hr = PROPVAR_ConvertNumber(propvarIn, 64, TRUE, &res); 286 *ret = !!res; 287 return hr; 288 } 289 290 HRESULT WINAPI PropVariantToStringAlloc(REFPROPVARIANT propvarIn, WCHAR **ret) 291 { 292 WCHAR *res = NULL; 293 HRESULT hr = S_OK; 294 295 TRACE("%p,%p semi-stub\n", propvarIn, ret); 296 297 switch(propvarIn->vt) 298 { 299 case VT_NULL: 300 res = CoTaskMemAlloc(1*sizeof(WCHAR)); 301 res[0] = '\0'; 302 break; 303 304 case VT_LPSTR: 305 if(propvarIn->u.pszVal) 306 { 307 DWORD len; 308 309 len = MultiByteToWideChar(CP_ACP, 0, propvarIn->u.pszVal, -1, NULL, 0); 310 res = CoTaskMemAlloc(len*sizeof(WCHAR)); 311 if(!res) 312 return E_OUTOFMEMORY; 313 314 MultiByteToWideChar(CP_ACP, 0, propvarIn->u.pszVal, -1, res, len); 315 } 316 break; 317 318 case VT_LPWSTR: 319 case VT_BSTR: 320 if (propvarIn->u.pwszVal) 321 { 322 DWORD size = (lstrlenW(propvarIn->u.pwszVal) + 1) * sizeof(WCHAR); 323 res = CoTaskMemAlloc(size); 324 if(!res) return E_OUTOFMEMORY; 325 memcpy(res, propvarIn->u.pwszVal, size); 326 } 327 break; 328 329 default: 330 FIXME("Unsupported conversion (%d)\n", propvarIn->vt); 331 hr = E_FAIL; 332 break; 333 } 334 335 *ret = res; 336 337 return hr; 338 } 339 340 PCWSTR WINAPI PropVariantToStringWithDefault(REFPROPVARIANT propvarIn, LPCWSTR pszDefault) 341 { 342 static const WCHAR str_empty[] = {0}; 343 if (propvarIn->vt == VT_BSTR) 344 { 345 if (propvarIn->u.bstrVal == NULL) 346 return str_empty; 347 348 return propvarIn->u.bstrVal; 349 } 350 351 if (propvarIn->vt == VT_LPWSTR && propvarIn->u.pwszVal != NULL) 352 return propvarIn->u.pwszVal; 353 354 return pszDefault; 355 } 356 357 358 /****************************************************************** 359 * PropVariantChangeType (PROPSYS.@) 360 */ 361 HRESULT WINAPI PropVariantChangeType(PROPVARIANT *ppropvarDest, REFPROPVARIANT propvarSrc, 362 PROPVAR_CHANGE_FLAGS flags, VARTYPE vt) 363 { 364 HRESULT hr; 365 366 FIXME("(%p, %p, %d, %d, %d): semi-stub!\n", ppropvarDest, propvarSrc, 367 propvarSrc->vt, flags, vt); 368 369 if (vt == propvarSrc->vt) 370 return PropVariantCopy(ppropvarDest, propvarSrc); 371 372 if (propvarSrc->vt == VT_FILETIME) 373 return PROPVAR_ConvertFILETIME(&propvarSrc->u.filetime, ppropvarDest, vt); 374 375 switch (vt) 376 { 377 case VT_I1: 378 { 379 LONGLONG res; 380 381 hr = PROPVAR_ConvertNumber(propvarSrc, 8, TRUE, &res); 382 if (SUCCEEDED(hr)) 383 { 384 ppropvarDest->vt = VT_I1; 385 ppropvarDest->u.cVal = (char)res; 386 } 387 return hr; 388 } 389 390 case VT_UI1: 391 { 392 LONGLONG res; 393 394 hr = PROPVAR_ConvertNumber(propvarSrc, 8, FALSE, &res); 395 if (SUCCEEDED(hr)) 396 { 397 ppropvarDest->vt = VT_UI1; 398 ppropvarDest->u.bVal = (UCHAR)res; 399 } 400 return hr; 401 } 402 403 case VT_I2: 404 { 405 SHORT res; 406 hr = PropVariantToInt16(propvarSrc, &res); 407 if (SUCCEEDED(hr)) 408 { 409 ppropvarDest->vt = VT_I2; 410 ppropvarDest->u.iVal = res; 411 } 412 return hr; 413 } 414 case VT_UI2: 415 { 416 USHORT res; 417 hr = PropVariantToUInt16(propvarSrc, &res); 418 if (SUCCEEDED(hr)) 419 { 420 ppropvarDest->vt = VT_UI2; 421 ppropvarDest->u.uiVal = res; 422 } 423 return hr; 424 } 425 case VT_I4: 426 { 427 LONG res; 428 hr = PropVariantToInt32(propvarSrc, &res); 429 if (SUCCEEDED(hr)) 430 { 431 ppropvarDest->vt = VT_I4; 432 ppropvarDest->u.lVal = res; 433 } 434 return hr; 435 } 436 case VT_UI4: 437 { 438 ULONG res; 439 hr = PropVariantToUInt32(propvarSrc, &res); 440 if (SUCCEEDED(hr)) 441 { 442 ppropvarDest->vt = VT_UI4; 443 ppropvarDest->u.ulVal = res; 444 } 445 return hr; 446 } 447 case VT_I8: 448 { 449 LONGLONG res; 450 hr = PropVariantToInt64(propvarSrc, &res); 451 if (SUCCEEDED(hr)) 452 { 453 ppropvarDest->vt = VT_I8; 454 ppropvarDest->u.hVal.QuadPart = res; 455 } 456 return hr; 457 } 458 case VT_UI8: 459 { 460 ULONGLONG res; 461 hr = PropVariantToUInt64(propvarSrc, &res); 462 if (SUCCEEDED(hr)) 463 { 464 ppropvarDest->vt = VT_UI8; 465 ppropvarDest->u.uhVal.QuadPart = res; 466 } 467 return hr; 468 } 469 470 case VT_LPWSTR: 471 case VT_BSTR: 472 { 473 WCHAR *res; 474 hr = PropVariantToStringAlloc(propvarSrc, &res); 475 if (SUCCEEDED(hr)) 476 { 477 ppropvarDest->vt = VT_LPWSTR; 478 ppropvarDest->u.pwszVal = res; 479 } 480 return hr; 481 } 482 483 case VT_LPSTR: 484 { 485 WCHAR *resW; 486 hr = PropVariantToStringAlloc(propvarSrc, &resW); 487 if (SUCCEEDED(hr)) 488 { 489 char *res; 490 DWORD len; 491 492 len = WideCharToMultiByte(CP_ACP, 0, resW, -1, NULL, 0, NULL, NULL); 493 res = CoTaskMemAlloc(len); 494 if (res) 495 { 496 WideCharToMultiByte(CP_ACP, 0, resW, -1, res, len, NULL, NULL); 497 ppropvarDest->vt = VT_LPSTR; 498 ppropvarDest->u.pszVal = res; 499 } 500 else 501 hr = E_OUTOFMEMORY; 502 503 CoTaskMemFree(resW); 504 } 505 return hr; 506 } 507 508 default: 509 FIXME("Unhandled dest type: %d\n", vt); 510 return E_FAIL; 511 } 512 } 513 514 static void PROPVAR_GUIDToWSTR(REFGUID guid, WCHAR *str) 515 { 516 static const WCHAR format[] = {'{','%','0','8','X','-','%','0','4','X','-','%','0','4','X', 517 '-','%','0','2','X','%','0','2','X','-','%','0','2','X','%','0','2','X','%','0','2','X', 518 '%','0','2','X','%','0','2','X','%','0','2','X','}',0}; 519 520 sprintfW(str, format, guid->Data1, guid->Data2, guid->Data3, 521 guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], 522 guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]); 523 } 524 525 HRESULT WINAPI InitPropVariantFromGUIDAsString(REFGUID guid, PROPVARIANT *ppropvar) 526 { 527 TRACE("(%p %p)\n", guid, ppropvar); 528 529 if(!guid) 530 return E_FAIL; 531 532 ppropvar->vt = VT_LPWSTR; 533 ppropvar->u.pwszVal = CoTaskMemAlloc(39*sizeof(WCHAR)); 534 if(!ppropvar->u.pwszVal) 535 return E_OUTOFMEMORY; 536 537 PROPVAR_GUIDToWSTR(guid, ppropvar->u.pwszVal); 538 return S_OK; 539 } 540 541 HRESULT WINAPI InitVariantFromGUIDAsString(REFGUID guid, VARIANT *pvar) 542 { 543 TRACE("(%p %p)\n", guid, pvar); 544 545 if(!guid) { 546 FIXME("guid == NULL\n"); 547 return E_FAIL; 548 } 549 550 V_VT(pvar) = VT_BSTR; 551 V_BSTR(pvar) = SysAllocStringLen(NULL, 38); 552 if(!V_BSTR(pvar)) 553 return E_OUTOFMEMORY; 554 555 PROPVAR_GUIDToWSTR(guid, V_BSTR(pvar)); 556 return S_OK; 557 } 558 559 HRESULT WINAPI InitPropVariantFromBuffer(const VOID *pv, UINT cb, PROPVARIANT *ppropvar) 560 { 561 TRACE("(%p %u %p)\n", pv, cb, ppropvar); 562 563 ppropvar->u.caub.pElems = CoTaskMemAlloc(cb); 564 if(!ppropvar->u.caub.pElems) 565 return E_OUTOFMEMORY; 566 567 ppropvar->vt = VT_VECTOR|VT_UI1; 568 ppropvar->u.caub.cElems = cb; 569 memcpy(ppropvar->u.caub.pElems, pv, cb); 570 return S_OK; 571 } 572 573 HRESULT WINAPI InitVariantFromBuffer(const VOID *pv, UINT cb, VARIANT *pvar) 574 { 575 SAFEARRAY *arr; 576 void *data; 577 HRESULT hres; 578 579 TRACE("(%p %u %p)\n", pv, cb, pvar); 580 581 arr = SafeArrayCreateVector(VT_UI1, 0, cb); 582 if(!arr) 583 return E_OUTOFMEMORY; 584 585 hres = SafeArrayAccessData(arr, &data); 586 if(FAILED(hres)) { 587 SafeArrayDestroy(arr); 588 return hres; 589 } 590 591 memcpy(data, pv, cb); 592 593 hres = SafeArrayUnaccessData(arr); 594 if(FAILED(hres)) { 595 SafeArrayDestroy(arr); 596 return hres; 597 } 598 599 V_VT(pvar) = VT_ARRAY|VT_UI1; 600 V_ARRAY(pvar) = arr; 601 return S_OK; 602 } 603 604 static inline DWORD PROPVAR_HexToNum(const WCHAR *hex) 605 { 606 DWORD ret; 607 608 if(hex[0]>='0' && hex[0]<='9') 609 ret = hex[0]-'0'; 610 else if(hex[0]>='a' && hex[0]<='f') 611 ret = hex[0]-'a'+10; 612 else if(hex[0]>='A' && hex[0]<='F') 613 ret = hex[0]-'A'+10; 614 else 615 return -1; 616 617 ret <<= 4; 618 if(hex[1]>='0' && hex[1]<='9') 619 return ret + hex[1]-'0'; 620 else if(hex[1]>='a' && hex[1]<='f') 621 return ret + hex[1]-'a'+10; 622 else if(hex[1]>='A' && hex[1]<='F') 623 return ret + hex[1]-'A'+10; 624 else 625 return -1; 626 } 627 628 static inline HRESULT PROPVAR_WCHARToGUID(const WCHAR *str, int len, GUID *guid) 629 { 630 DWORD i, val=0; 631 const WCHAR *p; 632 633 memset(guid, 0, sizeof(GUID)); 634 635 if(len!=38 || str[0]!='{' || str[9]!='-' || str[14]!='-' 636 || str[19]!='-' || str[24]!='-' || str[37]!='}') { 637 WARN("Error parsing %s\n", debugstr_w(str)); 638 return E_INVALIDARG; 639 } 640 641 p = str+1; 642 for(i=0; i<4 && val!=-1; i++) { 643 val = PROPVAR_HexToNum(p); 644 guid->Data1 = (guid->Data1<<8) + val; 645 p += 2; 646 } 647 p++; 648 for(i=0; i<2 && val!=-1; i++) { 649 val = PROPVAR_HexToNum(p); 650 guid->Data2 = (guid->Data2<<8) + val; 651 p += 2; 652 } 653 p++; 654 for(i=0; i<2 && val!=-1; i++) { 655 val = PROPVAR_HexToNum(p); 656 guid->Data3 = (guid->Data3<<8) + val; 657 p += 2; 658 } 659 p++; 660 for(i=0; i<8 && val!=-1; i++) { 661 if(i == 2) 662 p++; 663 664 val = guid->Data4[i] = PROPVAR_HexToNum(p); 665 p += 2; 666 } 667 668 if(val == -1) { 669 WARN("Error parsing %s\n", debugstr_w(str)); 670 memset(guid, 0, sizeof(GUID)); 671 return E_INVALIDARG; 672 } 673 return S_OK; 674 } 675 676 HRESULT WINAPI PropVariantToGUID(const PROPVARIANT *ppropvar, GUID *guid) 677 { 678 TRACE("%p %p)\n", ppropvar, guid); 679 680 switch(ppropvar->vt) { 681 case VT_BSTR: 682 return PROPVAR_WCHARToGUID(ppropvar->u.bstrVal, SysStringLen(ppropvar->u.bstrVal), guid); 683 case VT_LPWSTR: 684 return PROPVAR_WCHARToGUID(ppropvar->u.pwszVal, strlenW(ppropvar->u.pwszVal), guid); 685 686 default: 687 FIXME("unsupported vt: %d\n", ppropvar->vt); 688 return E_NOTIMPL; 689 } 690 } 691 692 HRESULT WINAPI VariantToGUID(const VARIANT *pvar, GUID *guid) 693 { 694 TRACE("(%p %p)\n", pvar, guid); 695 696 switch(V_VT(pvar)) { 697 case VT_BSTR: { 698 HRESULT hres = PROPVAR_WCHARToGUID(V_BSTR(pvar), SysStringLen(V_BSTR(pvar)), guid); 699 if(hres == E_INVALIDARG) 700 return E_FAIL; 701 return hres; 702 } 703 704 default: 705 FIXME("unsupported vt: %d\n", V_VT(pvar)); 706 return E_NOTIMPL; 707 } 708 } 709 710 static BOOL isemptyornull(const PROPVARIANT *propvar) 711 { 712 if (propvar->vt == VT_EMPTY || propvar->vt == VT_NULL) 713 return TRUE; 714 if ((propvar->vt & VT_ARRAY) == VT_ARRAY) 715 { 716 int i; 717 for (i=0; i<propvar->u.parray->cDims; i++) 718 { 719 if (propvar->u.parray->rgsabound[i].cElements != 0) 720 break; 721 } 722 return i == propvar->u.parray->cDims; 723 } 724 /* FIXME: vectors, byrefs, errors? */ 725 return FALSE; 726 } 727 728 INT WINAPI PropVariantCompareEx(REFPROPVARIANT propvar1, REFPROPVARIANT propvar2, 729 PROPVAR_COMPARE_UNIT unit, PROPVAR_COMPARE_FLAGS flags) 730 { 731 const PROPVARIANT *propvar2_converted; 732 PROPVARIANT propvar2_static; 733 HRESULT hr; 734 INT res=-1; 735 736 TRACE("%p,%p,%x,%x\n", propvar1, propvar2, unit, flags); 737 738 if (isemptyornull(propvar1)) 739 { 740 if (isemptyornull(propvar2)) 741 return 0; 742 return (flags & PVCF_TREATEMPTYASGREATERTHAN) ? 1 : -1; 743 } 744 745 if (isemptyornull(propvar2)) 746 return (flags & PVCF_TREATEMPTYASGREATERTHAN) ? -1 : 1; 747 748 if (propvar1->vt != propvar2->vt) 749 { 750 hr = PropVariantChangeType(&propvar2_static, propvar2, 0, propvar1->vt); 751 752 if (FAILED(hr)) 753 return -1; 754 755 propvar2_converted = &propvar2_static; 756 } 757 else 758 propvar2_converted = propvar2; 759 760 #define CMP_INT_VALUE(var) do { \ 761 if (propvar1->u.var > propvar2_converted->u.var) \ 762 res = 1; \ 763 else if (propvar1->u.var < propvar2_converted->u.var) \ 764 res = -1; \ 765 else \ 766 res = 0; \ 767 } while (0) 768 769 switch (propvar1->vt) 770 { 771 case VT_I1: 772 CMP_INT_VALUE(cVal); 773 break; 774 case VT_UI1: 775 CMP_INT_VALUE(bVal); 776 break; 777 case VT_I2: 778 CMP_INT_VALUE(iVal); 779 break; 780 case VT_UI2: 781 CMP_INT_VALUE(uiVal); 782 break; 783 case VT_I4: 784 CMP_INT_VALUE(lVal); 785 break; 786 case VT_UI4: 787 CMP_INT_VALUE(uiVal); 788 break; 789 case VT_I8: 790 CMP_INT_VALUE(hVal.QuadPart); 791 break; 792 case VT_UI8: 793 CMP_INT_VALUE(uhVal.QuadPart); 794 break; 795 case VT_BSTR: 796 case VT_LPWSTR: 797 /* FIXME: Use other string flags. */ 798 if (flags & (PVCF_USESTRCMPI | PVCF_USESTRCMPIC)) 799 res = lstrcmpiW(propvar1->u.bstrVal, propvar2_converted->u.bstrVal); 800 else 801 res = lstrcmpW(propvar1->u.bstrVal, propvar2_converted->u.bstrVal); 802 break; 803 case VT_LPSTR: 804 /* FIXME: Use other string flags. */ 805 if (flags & (PVCF_USESTRCMPI | PVCF_USESTRCMPIC)) 806 res = lstrcmpiA(propvar1->u.pszVal, propvar2_converted->u.pszVal); 807 else 808 res = lstrcmpA(propvar1->u.pszVal, propvar2_converted->u.pszVal); 809 break; 810 default: 811 FIXME("vartype %d not handled\n", propvar1->vt); 812 res = -1; 813 break; 814 } 815 816 if (propvar2_converted == &propvar2_static) 817 PropVariantClear(&propvar2_static); 818 819 return res; 820 } 821