advapi32/tests: Expand tests for performance keys.
[wine.git] / dlls / propsys / propvar.c
blob977fbebb9181b93b687857bd94babc22feffe16e
1 /*
2 * PropVariant implementation
4 * Copyright 2008 James Hawkins for CodeWeavers
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.
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.
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
22 #include <stdarg.h>
23 #include <stdio.h>
24 #include <stdlib.h>
26 #define NONAMELESSUNION
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"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(propsys);
41 static HRESULT PROPVAR_ConvertFILETIME(const FILETIME *ft, PROPVARIANT *ppropvarDest, VARTYPE vt)
43 SYSTEMTIME time;
45 FileTimeToSystemTime(ft, &time);
47 switch (vt)
49 case VT_LPSTR:
50 ppropvarDest->pszVal = HeapAlloc(GetProcessHeap(), 0, 64);
51 if (!ppropvarDest->pszVal)
52 return E_OUTOFMEMORY;
54 sprintf( ppropvarDest->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 );
59 return S_OK;
61 default:
62 FIXME("Unhandled target type: %d\n", vt);
65 return E_FAIL;
68 static HRESULT PROPVAR_ConvertNumber(REFPROPVARIANT pv, int dest_bits,
69 BOOL dest_signed, LONGLONG *res)
71 BOOL src_signed;
73 switch (pv->vt)
75 case VT_I1:
76 src_signed = TRUE;
77 *res = pv->cVal;
78 break;
79 case VT_UI1:
80 src_signed = FALSE;
81 *res = pv->bVal;
82 break;
83 case VT_I2:
84 src_signed = TRUE;
85 *res = pv->iVal;
86 break;
87 case VT_UI2:
88 src_signed = FALSE;
89 *res = pv->uiVal;
90 break;
91 case VT_I4:
92 src_signed = TRUE;
93 *res = pv->lVal;
94 break;
95 case VT_UI4:
96 src_signed = FALSE;
97 *res = pv->ulVal;
98 break;
99 case VT_I8:
100 src_signed = TRUE;
101 *res = pv->hVal.QuadPart;
102 break;
103 case VT_UI8:
104 src_signed = FALSE;
105 *res = pv->uhVal.QuadPart;
106 break;
107 case VT_EMPTY:
108 src_signed = FALSE;
109 *res = 0;
110 break;
111 case VT_LPSTR:
113 char *end;
114 *res = strtoll(pv->pszVal, &end, 0);
115 if (pv->pszVal == end)
116 return DISP_E_TYPEMISMATCH;
117 src_signed = *res < 0;
118 break;
120 case VT_LPWSTR:
121 case VT_BSTR:
123 WCHAR *end;
124 *res = wcstol(pv->pwszVal, &end, 0);
125 if (pv->pwszVal == end)
126 return DISP_E_TYPEMISMATCH;
127 src_signed = *res < 0;
128 break;
130 case VT_R8:
132 src_signed = TRUE;
133 *res = pv->dblVal;
134 break;
136 default:
137 FIXME("unhandled vt %d\n", pv->vt);
138 return E_NOTIMPL;
141 if (*res < 0 && src_signed != dest_signed)
142 return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
144 if (dest_bits < 64)
146 if (dest_signed)
148 if (*res >= ((LONGLONG)1 << (dest_bits-1)) ||
149 *res < ((LONGLONG)-1 << (dest_bits-1)))
150 return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
152 else
154 if ((ULONGLONG)(*res) >= ((ULONGLONG)1 << dest_bits))
155 return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
159 return S_OK;
162 HRESULT WINAPI PropVariantToDouble(REFPROPVARIANT propvarIn, double *ret)
164 LONGLONG res;
165 HRESULT hr;
167 TRACE("(%p, %p)\n", propvarIn, ret);
169 hr = PROPVAR_ConvertNumber(propvarIn, 64, TRUE, &res);
170 if (SUCCEEDED(hr)) *ret = (double)res;
171 return hr;
174 HRESULT WINAPI PropVariantToInt16(REFPROPVARIANT propvarIn, SHORT *ret)
176 LONGLONG res;
177 HRESULT hr;
179 TRACE("%p,%p\n", propvarIn, ret);
181 hr = PROPVAR_ConvertNumber(propvarIn, 16, TRUE, &res);
182 if (SUCCEEDED(hr)) *ret = (SHORT)res;
183 return hr;
186 HRESULT WINAPI PropVariantToInt32(REFPROPVARIANT propvarIn, LONG *ret)
188 LONGLONG res;
189 HRESULT hr;
191 TRACE("%p,%p\n", propvarIn, ret);
193 hr = PROPVAR_ConvertNumber(propvarIn, 32, TRUE, &res);
194 if (SUCCEEDED(hr)) *ret = (LONG)res;
195 return hr;
198 HRESULT WINAPI PropVariantToInt64(REFPROPVARIANT propvarIn, LONGLONG *ret)
200 LONGLONG res;
201 HRESULT hr;
203 TRACE("%p,%p\n", propvarIn, ret);
205 hr = PROPVAR_ConvertNumber(propvarIn, 64, TRUE, &res);
206 if (SUCCEEDED(hr)) *ret = res;
207 return hr;
210 HRESULT WINAPI PropVariantToUInt16(REFPROPVARIANT propvarIn, USHORT *ret)
212 LONGLONG res;
213 HRESULT hr;
215 TRACE("%p,%p\n", propvarIn, ret);
217 hr = PROPVAR_ConvertNumber(propvarIn, 16, FALSE, &res);
218 if (SUCCEEDED(hr)) *ret = (USHORT)res;
219 return hr;
222 HRESULT WINAPI PropVariantToUInt32(REFPROPVARIANT propvarIn, ULONG *ret)
224 LONGLONG res;
225 HRESULT hr;
227 TRACE("%p,%p\n", propvarIn, ret);
229 hr = PROPVAR_ConvertNumber(propvarIn, 32, FALSE, &res);
230 if (SUCCEEDED(hr)) *ret = (ULONG)res;
231 return hr;
234 HRESULT WINAPI PropVariantToUInt64(REFPROPVARIANT propvarIn, ULONGLONG *ret)
236 LONGLONG res;
237 HRESULT hr;
239 TRACE("%p,%p\n", propvarIn, ret);
241 hr = PROPVAR_ConvertNumber(propvarIn, 64, FALSE, &res);
242 if (SUCCEEDED(hr)) *ret = (ULONGLONG)res;
243 return hr;
246 HRESULT WINAPI PropVariantToBoolean(REFPROPVARIANT propvarIn, BOOL *ret)
248 LONGLONG res;
249 HRESULT hr;
251 TRACE("%p,%p\n", propvarIn, ret);
253 *ret = FALSE;
255 switch (propvarIn->vt)
257 case VT_BOOL:
258 *ret = propvarIn->boolVal == VARIANT_TRUE;
259 return S_OK;
261 case VT_LPWSTR:
262 case VT_BSTR:
263 if (!propvarIn->pwszVal)
264 return DISP_E_TYPEMISMATCH;
266 if (!lstrcmpiW(propvarIn->pwszVal, L"true") || !lstrcmpW(propvarIn->pwszVal, L"#TRUE#"))
268 *ret = TRUE;
269 return S_OK;
272 if (!lstrcmpiW(propvarIn->pwszVal, L"false") || !lstrcmpW(propvarIn->pwszVal, L"#FALSE#"))
274 *ret = FALSE;
275 return S_OK;
277 break;
279 case VT_LPSTR:
280 if (!propvarIn->pszVal)
281 return DISP_E_TYPEMISMATCH;
283 if (!lstrcmpiA(propvarIn->pszVal, "true") || !lstrcmpA(propvarIn->pszVal, "#TRUE#"))
285 *ret = TRUE;
286 return S_OK;
289 if (!lstrcmpiA(propvarIn->pszVal, "false") || !lstrcmpA(propvarIn->pszVal, "#FALSE#"))
291 *ret = FALSE;
292 return S_OK;
294 break;
297 hr = PROPVAR_ConvertNumber(propvarIn, 64, TRUE, &res);
298 *ret = !!res;
299 return hr;
302 HRESULT WINAPI PropVariantToBuffer(REFPROPVARIANT propvarIn, void *ret, UINT cb)
304 HRESULT hr = S_OK;
306 TRACE("(%p, %p, %d)\n", propvarIn, ret, cb);
308 switch(propvarIn->vt)
310 case VT_VECTOR|VT_UI1:
311 if(cb > propvarIn->caub.cElems)
312 return E_FAIL;
313 memcpy(ret, propvarIn->caub.pElems, cb);
314 break;
315 case VT_ARRAY|VT_UI1:
316 FIXME("Unsupported type: VT_ARRAY|VT_UI1\n");
317 hr = E_NOTIMPL;
318 break;
319 default:
320 WARN("Unexpected type: %x\n", propvarIn->vt);
321 hr = E_INVALIDARG;
324 return hr;
328 HRESULT WINAPI PropVariantToString(REFPROPVARIANT propvarIn, PWSTR ret, UINT cch)
330 HRESULT hr;
331 WCHAR *stringW = NULL;
333 TRACE("(%p, %p, %d)\n", propvarIn, ret, cch);
335 ret[0] = '\0';
337 if(!cch)
338 return E_INVALIDARG;
340 hr = PropVariantToStringAlloc(propvarIn, &stringW);
341 if(SUCCEEDED(hr))
343 if(lstrlenW(stringW) >= cch)
344 hr = STRSAFE_E_INSUFFICIENT_BUFFER;
345 lstrcpynW(ret, stringW, cch);
346 CoTaskMemFree(stringW);
349 return hr;
352 HRESULT WINAPI PropVariantToStringAlloc(REFPROPVARIANT propvarIn, WCHAR **ret)
354 WCHAR *res = NULL;
355 HRESULT hr = S_OK;
357 TRACE("%p,%p semi-stub\n", propvarIn, ret);
359 switch(propvarIn->vt)
361 case VT_EMPTY:
362 case VT_NULL:
363 res = CoTaskMemAlloc(1*sizeof(WCHAR));
364 res[0] = '\0';
365 break;
367 case VT_LPSTR:
368 if(propvarIn->pszVal)
370 DWORD len;
372 len = MultiByteToWideChar(CP_ACP, 0, propvarIn->pszVal, -1, NULL, 0);
373 res = CoTaskMemAlloc(len*sizeof(WCHAR));
374 if(!res)
375 return E_OUTOFMEMORY;
377 MultiByteToWideChar(CP_ACP, 0, propvarIn->pszVal, -1, res, len);
379 break;
381 case VT_LPWSTR:
382 case VT_BSTR:
383 if (propvarIn->pwszVal)
385 DWORD size = (lstrlenW(propvarIn->pwszVal) + 1) * sizeof(WCHAR);
386 res = CoTaskMemAlloc(size);
387 if(!res) return E_OUTOFMEMORY;
388 memcpy(res, propvarIn->pwszVal, size);
390 break;
392 default:
393 FIXME("Unsupported conversion (%d)\n", propvarIn->vt);
394 hr = E_FAIL;
395 break;
398 *ret = res;
400 return hr;
403 PCWSTR WINAPI PropVariantToStringWithDefault(REFPROPVARIANT propvarIn, LPCWSTR pszDefault)
405 if (propvarIn->vt == VT_BSTR)
407 if (propvarIn->bstrVal == NULL)
408 return L"";
410 return propvarIn->bstrVal;
413 if (propvarIn->vt == VT_LPWSTR && propvarIn->pwszVal != NULL)
414 return propvarIn->pwszVal;
416 return pszDefault;
420 /******************************************************************
421 * PropVariantChangeType (PROPSYS.@)
423 HRESULT WINAPI PropVariantChangeType(PROPVARIANT *ppropvarDest, REFPROPVARIANT propvarSrc,
424 PROPVAR_CHANGE_FLAGS flags, VARTYPE vt)
426 HRESULT hr;
428 FIXME("(%p, %p, %d, %d, %d): semi-stub!\n", ppropvarDest, propvarSrc,
429 propvarSrc->vt, flags, vt);
431 if (vt == propvarSrc->vt)
432 return PropVariantCopy(ppropvarDest, propvarSrc);
434 if (propvarSrc->vt == VT_FILETIME)
435 return PROPVAR_ConvertFILETIME(&propvarSrc->filetime, ppropvarDest, vt);
437 switch (vt)
439 case VT_I1:
441 LONGLONG res;
443 hr = PROPVAR_ConvertNumber(propvarSrc, 8, TRUE, &res);
444 if (SUCCEEDED(hr))
446 ppropvarDest->vt = VT_I1;
447 ppropvarDest->cVal = (char)res;
449 return hr;
452 case VT_UI1:
454 LONGLONG res;
456 hr = PROPVAR_ConvertNumber(propvarSrc, 8, FALSE, &res);
457 if (SUCCEEDED(hr))
459 ppropvarDest->vt = VT_UI1;
460 ppropvarDest->bVal = (UCHAR)res;
462 return hr;
465 case VT_I2:
467 SHORT res;
468 hr = PropVariantToInt16(propvarSrc, &res);
469 if (SUCCEEDED(hr))
471 ppropvarDest->vt = VT_I2;
472 ppropvarDest->iVal = res;
474 return hr;
476 case VT_UI2:
478 USHORT res;
479 hr = PropVariantToUInt16(propvarSrc, &res);
480 if (SUCCEEDED(hr))
482 ppropvarDest->vt = VT_UI2;
483 ppropvarDest->uiVal = res;
485 return hr;
487 case VT_I4:
489 LONG res;
490 hr = PropVariantToInt32(propvarSrc, &res);
491 if (SUCCEEDED(hr))
493 ppropvarDest->vt = VT_I4;
494 ppropvarDest->lVal = res;
496 return hr;
498 case VT_UI4:
500 ULONG res;
501 hr = PropVariantToUInt32(propvarSrc, &res);
502 if (SUCCEEDED(hr))
504 ppropvarDest->vt = VT_UI4;
505 ppropvarDest->ulVal = res;
507 return hr;
509 case VT_I8:
511 LONGLONG res;
512 hr = PropVariantToInt64(propvarSrc, &res);
513 if (SUCCEEDED(hr))
515 ppropvarDest->vt = VT_I8;
516 ppropvarDest->hVal.QuadPart = res;
518 return hr;
520 case VT_UI8:
522 ULONGLONG res;
523 hr = PropVariantToUInt64(propvarSrc, &res);
524 if (SUCCEEDED(hr))
526 ppropvarDest->vt = VT_UI8;
527 ppropvarDest->uhVal.QuadPart = res;
529 return hr;
532 case VT_LPWSTR:
533 case VT_BSTR:
535 WCHAR *res;
536 hr = PropVariantToStringAlloc(propvarSrc, &res);
537 if (SUCCEEDED(hr))
539 ppropvarDest->vt = VT_LPWSTR;
540 ppropvarDest->pwszVal = res;
542 return hr;
545 case VT_LPSTR:
547 WCHAR *resW;
548 hr = PropVariantToStringAlloc(propvarSrc, &resW);
549 if (SUCCEEDED(hr))
551 char *res;
552 DWORD len;
554 len = WideCharToMultiByte(CP_ACP, 0, resW, -1, NULL, 0, NULL, NULL);
555 res = CoTaskMemAlloc(len);
556 if (res)
558 WideCharToMultiByte(CP_ACP, 0, resW, -1, res, len, NULL, NULL);
559 ppropvarDest->vt = VT_LPSTR;
560 ppropvarDest->pszVal = res;
562 else
563 hr = E_OUTOFMEMORY;
565 CoTaskMemFree(resW);
567 return hr;
570 default:
571 FIXME("Unhandled dest type: %d\n", vt);
572 return E_FAIL;
576 static void PROPVAR_GUIDToWSTR(REFGUID guid, WCHAR *str)
578 swprintf(str, 39, L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", guid->Data1,
579 guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2],
580 guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
583 HRESULT WINAPI InitPropVariantFromGUIDAsString(REFGUID guid, PROPVARIANT *ppropvar)
585 TRACE("(%p %p)\n", guid, ppropvar);
587 if(!guid)
588 return E_FAIL;
590 ppropvar->vt = VT_LPWSTR;
591 ppropvar->pwszVal = CoTaskMemAlloc(39*sizeof(WCHAR));
592 if(!ppropvar->pwszVal)
593 return E_OUTOFMEMORY;
595 PROPVAR_GUIDToWSTR(guid, ppropvar->pwszVal);
596 return S_OK;
599 HRESULT WINAPI InitVariantFromGUIDAsString(REFGUID guid, VARIANT *pvar)
601 TRACE("(%p %p)\n", guid, pvar);
603 if(!guid) {
604 FIXME("guid == NULL\n");
605 return E_FAIL;
608 V_VT(pvar) = VT_BSTR;
609 V_BSTR(pvar) = SysAllocStringLen(NULL, 38);
610 if(!V_BSTR(pvar))
611 return E_OUTOFMEMORY;
613 PROPVAR_GUIDToWSTR(guid, V_BSTR(pvar));
614 return S_OK;
617 HRESULT WINAPI InitPropVariantFromBuffer(const VOID *pv, UINT cb, PROPVARIANT *ppropvar)
619 TRACE("(%p %u %p)\n", pv, cb, ppropvar);
621 ppropvar->caub.pElems = CoTaskMemAlloc(cb);
622 if(!ppropvar->caub.pElems)
623 return E_OUTOFMEMORY;
625 ppropvar->vt = VT_VECTOR|VT_UI1;
626 ppropvar->caub.cElems = cb;
627 memcpy(ppropvar->caub.pElems, pv, cb);
628 return S_OK;
631 HRESULT WINAPI InitPropVariantFromCLSID(REFCLSID clsid, PROPVARIANT *ppropvar)
633 TRACE("(%s %p)\n", debugstr_guid(clsid), ppropvar);
635 ppropvar->puuid = CoTaskMemAlloc(sizeof(*ppropvar->puuid));
636 if(!ppropvar->puuid)
637 return E_OUTOFMEMORY;
639 ppropvar->vt = VT_CLSID;
640 memcpy(ppropvar->puuid, clsid, sizeof(*ppropvar->puuid));
641 return S_OK;
644 HRESULT WINAPI InitVariantFromBuffer(const VOID *pv, UINT cb, VARIANT *pvar)
646 SAFEARRAY *arr;
647 void *data;
648 HRESULT hres;
650 TRACE("(%p %u %p)\n", pv, cb, pvar);
652 arr = SafeArrayCreateVector(VT_UI1, 0, cb);
653 if(!arr)
654 return E_OUTOFMEMORY;
656 hres = SafeArrayAccessData(arr, &data);
657 if(FAILED(hres)) {
658 SafeArrayDestroy(arr);
659 return hres;
662 memcpy(data, pv, cb);
664 hres = SafeArrayUnaccessData(arr);
665 if(FAILED(hres)) {
666 SafeArrayDestroy(arr);
667 return hres;
670 V_VT(pvar) = VT_ARRAY|VT_UI1;
671 V_ARRAY(pvar) = arr;
672 return S_OK;
675 static inline DWORD PROPVAR_HexToNum(const WCHAR *hex)
677 DWORD ret;
679 if(hex[0]>='0' && hex[0]<='9')
680 ret = hex[0]-'0';
681 else if(hex[0]>='a' && hex[0]<='f')
682 ret = hex[0]-'a'+10;
683 else if(hex[0]>='A' && hex[0]<='F')
684 ret = hex[0]-'A'+10;
685 else
686 return -1;
688 ret <<= 4;
689 if(hex[1]>='0' && hex[1]<='9')
690 return ret + hex[1]-'0';
691 else if(hex[1]>='a' && hex[1]<='f')
692 return ret + hex[1]-'a'+10;
693 else if(hex[1]>='A' && hex[1]<='F')
694 return ret + hex[1]-'A'+10;
695 else
696 return -1;
699 static inline HRESULT PROPVAR_WCHARToGUID(const WCHAR *str, int len, GUID *guid)
701 DWORD i, val=0;
702 const WCHAR *p;
704 memset(guid, 0, sizeof(GUID));
706 if(len!=38 || str[0]!='{' || str[9]!='-' || str[14]!='-'
707 || str[19]!='-' || str[24]!='-' || str[37]!='}') {
708 WARN("Error parsing %s\n", debugstr_w(str));
709 return E_INVALIDARG;
712 p = str+1;
713 for(i=0; i<4 && val!=-1; i++) {
714 val = PROPVAR_HexToNum(p);
715 guid->Data1 = (guid->Data1<<8) + val;
716 p += 2;
718 p++;
719 for(i=0; i<2 && val!=-1; i++) {
720 val = PROPVAR_HexToNum(p);
721 guid->Data2 = (guid->Data2<<8) + val;
722 p += 2;
724 p++;
725 for(i=0; i<2 && val!=-1; i++) {
726 val = PROPVAR_HexToNum(p);
727 guid->Data3 = (guid->Data3<<8) + val;
728 p += 2;
730 p++;
731 for(i=0; i<8 && val!=-1; i++) {
732 if(i == 2)
733 p++;
735 val = guid->Data4[i] = PROPVAR_HexToNum(p);
736 p += 2;
739 if(val == -1) {
740 WARN("Error parsing %s\n", debugstr_w(str));
741 memset(guid, 0, sizeof(GUID));
742 return E_INVALIDARG;
744 return S_OK;
747 HRESULT WINAPI PropVariantToGUID(const PROPVARIANT *ppropvar, GUID *guid)
749 TRACE("%p %p)\n", ppropvar, guid);
751 switch(ppropvar->vt) {
752 case VT_BSTR:
753 return PROPVAR_WCHARToGUID(ppropvar->bstrVal, SysStringLen(ppropvar->bstrVal), guid);
754 case VT_LPWSTR:
755 return PROPVAR_WCHARToGUID(ppropvar->pwszVal, lstrlenW(ppropvar->pwszVal), guid);
756 case VT_CLSID:
757 memcpy(guid, ppropvar->puuid, sizeof(*ppropvar->puuid));
758 return S_OK;
760 default:
761 FIXME("unsupported vt: %d\n", ppropvar->vt);
762 return E_NOTIMPL;
766 HRESULT WINAPI VariantToGUID(const VARIANT *pvar, GUID *guid)
768 TRACE("(%p %p)\n", pvar, guid);
770 switch(V_VT(pvar)) {
771 case VT_BSTR: {
772 HRESULT hres = PROPVAR_WCHARToGUID(V_BSTR(pvar), SysStringLen(V_BSTR(pvar)), guid);
773 if(hres == E_INVALIDARG)
774 return E_FAIL;
775 return hres;
778 default:
779 FIXME("unsupported vt: %d\n", V_VT(pvar));
780 return E_NOTIMPL;
784 static BOOL isemptyornull(const PROPVARIANT *propvar)
786 if (propvar->vt == VT_EMPTY || propvar->vt == VT_NULL)
787 return TRUE;
788 if ((propvar->vt & VT_ARRAY) == VT_ARRAY)
790 int i;
791 for (i=0; i<propvar->parray->cDims; i++)
793 if (propvar->parray->rgsabound[i].cElements != 0)
794 break;
796 return i == propvar->parray->cDims;
798 if (propvar->vt == VT_CLSID)
799 return !propvar->puuid;
801 if (propvar->vt & VT_VECTOR)
802 return !propvar->caub.cElems;
804 /* FIXME: byrefs, errors? */
805 return FALSE;
808 INT WINAPI PropVariantCompareEx(REFPROPVARIANT propvar1, REFPROPVARIANT propvar2,
809 PROPVAR_COMPARE_UNIT unit, PROPVAR_COMPARE_FLAGS flags)
811 const PROPVARIANT *propvar2_converted;
812 PROPVARIANT propvar2_static;
813 unsigned int count;
814 HRESULT hr;
815 INT res=-1;
817 TRACE("%p,%p,%x,%x\n", propvar1, propvar2, unit, flags);
819 if (isemptyornull(propvar1))
821 if (isemptyornull(propvar2))
822 return 0;
823 return (flags & PVCF_TREATEMPTYASGREATERTHAN) ? 1 : -1;
826 if (isemptyornull(propvar2))
827 return (flags & PVCF_TREATEMPTYASGREATERTHAN) ? -1 : 1;
829 if (propvar1->vt != propvar2->vt)
831 hr = PropVariantChangeType(&propvar2_static, propvar2, 0, propvar1->vt);
833 if (FAILED(hr))
834 return -1;
836 propvar2_converted = &propvar2_static;
838 else
839 propvar2_converted = propvar2;
841 #define CMP_NUM_VALUE(var) do { \
842 if (propvar1->var > propvar2_converted->var) \
843 res = 1; \
844 else if (propvar1->var < propvar2_converted->var) \
845 res = -1; \
846 else \
847 res = 0; \
848 } while (0)
850 switch (propvar1->vt)
852 case VT_I1:
853 CMP_NUM_VALUE(cVal);
854 break;
855 case VT_UI1:
856 CMP_NUM_VALUE(bVal);
857 break;
858 case VT_I2:
859 CMP_NUM_VALUE(iVal);
860 break;
861 case VT_UI2:
862 CMP_NUM_VALUE(uiVal);
863 break;
864 case VT_I4:
865 CMP_NUM_VALUE(lVal);
866 break;
867 case VT_UI4:
868 CMP_NUM_VALUE(uiVal);
869 break;
870 case VT_I8:
871 CMP_NUM_VALUE(hVal.QuadPart);
872 break;
873 case VT_UI8:
874 CMP_NUM_VALUE(uhVal.QuadPart);
875 break;
876 case VT_R4:
877 CMP_NUM_VALUE(fltVal);
878 break;
879 case VT_R8:
880 CMP_NUM_VALUE(dblVal);
881 break;
882 case VT_BSTR:
883 case VT_LPWSTR:
884 /* FIXME: Use other string flags. */
885 if (flags & (PVCF_USESTRCMPI | PVCF_USESTRCMPIC))
886 res = lstrcmpiW(propvar1->bstrVal, propvar2_converted->bstrVal);
887 else
888 res = lstrcmpW(propvar1->bstrVal, propvar2_converted->bstrVal);
889 break;
890 case VT_LPSTR:
891 /* FIXME: Use other string flags. */
892 if (flags & (PVCF_USESTRCMPI | PVCF_USESTRCMPIC))
893 res = lstrcmpiA(propvar1->pszVal, propvar2_converted->pszVal);
894 else
895 res = lstrcmpA(propvar1->pszVal, propvar2_converted->pszVal);
896 break;
897 case VT_CLSID:
898 res = memcmp(propvar1->puuid, propvar2->puuid, sizeof(*propvar1->puuid));
899 if (res) res = res > 0 ? 1 : -1;
900 break;
901 case VT_VECTOR | VT_UI1:
902 count = min(propvar1->caub.cElems, propvar2->caub.cElems);
903 res = count ? memcmp(propvar1->caub.pElems, propvar2->caub.pElems, sizeof(*propvar1->caub.pElems) * count) : 0;
904 if (res) res = res > 0 ? 1 : -1;
905 if (!res && propvar1->caub.cElems != propvar2->caub.cElems)
906 res = propvar1->caub.cElems > propvar2->caub.cElems ? 1 : -1;
907 break;
908 default:
909 FIXME("vartype %#x not handled\n", propvar1->vt);
910 res = -1;
911 break;
914 if (propvar2_converted == &propvar2_static)
915 PropVariantClear(&propvar2_static);
917 return res;