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