propsys: Implement VariantToStringWithDefault.
[wine.git] / dlls / propsys / propvar.c
blobcd92912fde5cb27c3fa6f4e6e9046b863c68a7b1
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;
419 /******************************************************************
420 * VariantToStringWithDefault (PROPSYS.@)
422 PCWSTR WINAPI VariantToStringWithDefault(const VARIANT *pvar, const WCHAR *default_value)
424 TRACE("%s, %s.\n", debugstr_variant(pvar), debugstr_w(default_value));
426 if (V_VT(pvar) == (VT_BYREF | VT_VARIANT)) pvar = V_VARIANTREF(pvar);
427 if (V_VT(pvar) == (VT_BYREF | VT_BSTR) || V_VT(pvar) == VT_BSTR)
429 BSTR ret = V_ISBYREF(pvar) ? *V_BSTRREF(pvar) : V_BSTR(pvar);
430 return ret ? ret : L"";
433 return default_value;
436 /******************************************************************
437 * PropVariantChangeType (PROPSYS.@)
439 HRESULT WINAPI PropVariantChangeType(PROPVARIANT *ppropvarDest, REFPROPVARIANT propvarSrc,
440 PROPVAR_CHANGE_FLAGS flags, VARTYPE vt)
442 HRESULT hr;
444 FIXME("(%p, %p, %d, %d, %d): semi-stub!\n", ppropvarDest, propvarSrc,
445 propvarSrc->vt, flags, vt);
447 if (vt == propvarSrc->vt)
448 return PropVariantCopy(ppropvarDest, propvarSrc);
450 if (propvarSrc->vt == VT_FILETIME)
451 return PROPVAR_ConvertFILETIME(&propvarSrc->filetime, ppropvarDest, vt);
453 switch (vt)
455 case VT_I1:
457 LONGLONG res;
459 hr = PROPVAR_ConvertNumber(propvarSrc, 8, TRUE, &res);
460 if (SUCCEEDED(hr))
462 ppropvarDest->vt = VT_I1;
463 ppropvarDest->cVal = (char)res;
465 return hr;
468 case VT_UI1:
470 LONGLONG res;
472 hr = PROPVAR_ConvertNumber(propvarSrc, 8, FALSE, &res);
473 if (SUCCEEDED(hr))
475 ppropvarDest->vt = VT_UI1;
476 ppropvarDest->bVal = (UCHAR)res;
478 return hr;
481 case VT_I2:
483 SHORT res;
484 hr = PropVariantToInt16(propvarSrc, &res);
485 if (SUCCEEDED(hr))
487 ppropvarDest->vt = VT_I2;
488 ppropvarDest->iVal = res;
490 return hr;
492 case VT_UI2:
494 USHORT res;
495 hr = PropVariantToUInt16(propvarSrc, &res);
496 if (SUCCEEDED(hr))
498 ppropvarDest->vt = VT_UI2;
499 ppropvarDest->uiVal = res;
501 return hr;
503 case VT_I4:
505 LONG res;
506 hr = PropVariantToInt32(propvarSrc, &res);
507 if (SUCCEEDED(hr))
509 ppropvarDest->vt = VT_I4;
510 ppropvarDest->lVal = res;
512 return hr;
514 case VT_UI4:
516 ULONG res;
517 hr = PropVariantToUInt32(propvarSrc, &res);
518 if (SUCCEEDED(hr))
520 ppropvarDest->vt = VT_UI4;
521 ppropvarDest->ulVal = res;
523 return hr;
525 case VT_I8:
527 LONGLONG res;
528 hr = PropVariantToInt64(propvarSrc, &res);
529 if (SUCCEEDED(hr))
531 ppropvarDest->vt = VT_I8;
532 ppropvarDest->hVal.QuadPart = res;
534 return hr;
536 case VT_UI8:
538 ULONGLONG res;
539 hr = PropVariantToUInt64(propvarSrc, &res);
540 if (SUCCEEDED(hr))
542 ppropvarDest->vt = VT_UI8;
543 ppropvarDest->uhVal.QuadPart = res;
545 return hr;
548 case VT_LPWSTR:
549 case VT_BSTR:
551 WCHAR *res;
552 hr = PropVariantToStringAlloc(propvarSrc, &res);
553 if (SUCCEEDED(hr))
555 ppropvarDest->vt = VT_LPWSTR;
556 ppropvarDest->pwszVal = res;
558 return hr;
561 case VT_LPSTR:
563 WCHAR *resW;
564 hr = PropVariantToStringAlloc(propvarSrc, &resW);
565 if (SUCCEEDED(hr))
567 char *res;
568 DWORD len;
570 len = WideCharToMultiByte(CP_ACP, 0, resW, -1, NULL, 0, NULL, NULL);
571 res = CoTaskMemAlloc(len);
572 if (res)
574 WideCharToMultiByte(CP_ACP, 0, resW, -1, res, len, NULL, NULL);
575 ppropvarDest->vt = VT_LPSTR;
576 ppropvarDest->pszVal = res;
578 else
579 hr = E_OUTOFMEMORY;
581 CoTaskMemFree(resW);
583 return hr;
586 default:
587 FIXME("Unhandled dest type: %d\n", vt);
588 return E_FAIL;
592 static void PROPVAR_GUIDToWSTR(REFGUID guid, WCHAR *str)
594 swprintf(str, 39, L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", guid->Data1,
595 guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2],
596 guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
599 HRESULT WINAPI InitPropVariantFromGUIDAsString(REFGUID guid, PROPVARIANT *ppropvar)
601 TRACE("(%p %p)\n", guid, ppropvar);
603 if(!guid)
604 return E_FAIL;
606 ppropvar->vt = VT_LPWSTR;
607 ppropvar->pwszVal = CoTaskMemAlloc(39*sizeof(WCHAR));
608 if(!ppropvar->pwszVal)
609 return E_OUTOFMEMORY;
611 PROPVAR_GUIDToWSTR(guid, ppropvar->pwszVal);
612 return S_OK;
615 HRESULT WINAPI InitVariantFromGUIDAsString(REFGUID guid, VARIANT *pvar)
617 TRACE("(%p %p)\n", guid, pvar);
619 if(!guid) {
620 FIXME("guid == NULL\n");
621 return E_FAIL;
624 V_VT(pvar) = VT_BSTR;
625 V_BSTR(pvar) = SysAllocStringLen(NULL, 38);
626 if(!V_BSTR(pvar))
627 return E_OUTOFMEMORY;
629 PROPVAR_GUIDToWSTR(guid, V_BSTR(pvar));
630 return S_OK;
633 HRESULT WINAPI InitPropVariantFromBuffer(const VOID *pv, UINT cb, PROPVARIANT *ppropvar)
635 TRACE("(%p %u %p)\n", pv, cb, ppropvar);
637 ppropvar->caub.pElems = CoTaskMemAlloc(cb);
638 if(!ppropvar->caub.pElems)
639 return E_OUTOFMEMORY;
641 ppropvar->vt = VT_VECTOR|VT_UI1;
642 ppropvar->caub.cElems = cb;
643 memcpy(ppropvar->caub.pElems, pv, cb);
644 return S_OK;
647 HRESULT WINAPI InitPropVariantFromCLSID(REFCLSID clsid, PROPVARIANT *ppropvar)
649 TRACE("(%s %p)\n", debugstr_guid(clsid), ppropvar);
651 ppropvar->puuid = CoTaskMemAlloc(sizeof(*ppropvar->puuid));
652 if(!ppropvar->puuid)
653 return E_OUTOFMEMORY;
655 ppropvar->vt = VT_CLSID;
656 memcpy(ppropvar->puuid, clsid, sizeof(*ppropvar->puuid));
657 return S_OK;
660 HRESULT WINAPI InitVariantFromBuffer(const VOID *pv, UINT cb, VARIANT *pvar)
662 SAFEARRAY *arr;
663 void *data;
664 HRESULT hres;
666 TRACE("(%p %u %p)\n", pv, cb, pvar);
668 arr = SafeArrayCreateVector(VT_UI1, 0, cb);
669 if(!arr)
670 return E_OUTOFMEMORY;
672 hres = SafeArrayAccessData(arr, &data);
673 if(FAILED(hres)) {
674 SafeArrayDestroy(arr);
675 return hres;
678 memcpy(data, pv, cb);
680 hres = SafeArrayUnaccessData(arr);
681 if(FAILED(hres)) {
682 SafeArrayDestroy(arr);
683 return hres;
686 V_VT(pvar) = VT_ARRAY|VT_UI1;
687 V_ARRAY(pvar) = arr;
688 return S_OK;
691 HRESULT WINAPI InitVariantFromFileTime(const FILETIME *ft, VARIANT *var)
693 SYSTEMTIME st;
695 TRACE("%p, %p\n", ft, var);
697 VariantInit(var);
698 if (!FileTimeToSystemTime(ft, &st))
699 return E_INVALIDARG;
700 if (!SystemTimeToVariantTime(&st, &V_DATE(var)))
701 return E_INVALIDARG;
702 V_VT(var) = VT_DATE;
703 return S_OK;
706 static inline DWORD PROPVAR_HexToNum(const WCHAR *hex)
708 DWORD ret;
710 if(hex[0]>='0' && hex[0]<='9')
711 ret = hex[0]-'0';
712 else if(hex[0]>='a' && hex[0]<='f')
713 ret = hex[0]-'a'+10;
714 else if(hex[0]>='A' && hex[0]<='F')
715 ret = hex[0]-'A'+10;
716 else
717 return -1;
719 ret <<= 4;
720 if(hex[1]>='0' && hex[1]<='9')
721 return ret + hex[1]-'0';
722 else if(hex[1]>='a' && hex[1]<='f')
723 return ret + hex[1]-'a'+10;
724 else if(hex[1]>='A' && hex[1]<='F')
725 return ret + hex[1]-'A'+10;
726 else
727 return -1;
730 static inline HRESULT PROPVAR_WCHARToGUID(const WCHAR *str, int len, GUID *guid)
732 DWORD i, val=0;
733 const WCHAR *p;
735 memset(guid, 0, sizeof(GUID));
737 if(len!=38 || str[0]!='{' || str[9]!='-' || str[14]!='-'
738 || str[19]!='-' || str[24]!='-' || str[37]!='}') {
739 WARN("Error parsing %s\n", debugstr_w(str));
740 return E_INVALIDARG;
743 p = str+1;
744 for(i=0; i<4 && val!=-1; i++) {
745 val = PROPVAR_HexToNum(p);
746 guid->Data1 = (guid->Data1<<8) + val;
747 p += 2;
749 p++;
750 for(i=0; i<2 && val!=-1; i++) {
751 val = PROPVAR_HexToNum(p);
752 guid->Data2 = (guid->Data2<<8) + val;
753 p += 2;
755 p++;
756 for(i=0; i<2 && val!=-1; i++) {
757 val = PROPVAR_HexToNum(p);
758 guid->Data3 = (guid->Data3<<8) + val;
759 p += 2;
761 p++;
762 for(i=0; i<8 && val!=-1; i++) {
763 if(i == 2)
764 p++;
766 val = guid->Data4[i] = PROPVAR_HexToNum(p);
767 p += 2;
770 if(val == -1) {
771 WARN("Error parsing %s\n", debugstr_w(str));
772 memset(guid, 0, sizeof(GUID));
773 return E_INVALIDARG;
775 return S_OK;
778 HRESULT WINAPI PropVariantToGUID(const PROPVARIANT *ppropvar, GUID *guid)
780 TRACE("%p %p)\n", ppropvar, guid);
782 switch(ppropvar->vt) {
783 case VT_BSTR:
784 return PROPVAR_WCHARToGUID(ppropvar->bstrVal, SysStringLen(ppropvar->bstrVal), guid);
785 case VT_LPWSTR:
786 return PROPVAR_WCHARToGUID(ppropvar->pwszVal, lstrlenW(ppropvar->pwszVal), guid);
787 case VT_CLSID:
788 memcpy(guid, ppropvar->puuid, sizeof(*ppropvar->puuid));
789 return S_OK;
791 default:
792 FIXME("unsupported vt: %d\n", ppropvar->vt);
793 return E_NOTIMPL;
797 HRESULT WINAPI VariantToGUID(const VARIANT *pvar, GUID *guid)
799 TRACE("(%p %p)\n", pvar, guid);
801 switch(V_VT(pvar)) {
802 case VT_BSTR: {
803 HRESULT hres = PROPVAR_WCHARToGUID(V_BSTR(pvar), SysStringLen(V_BSTR(pvar)), guid);
804 if(hres == E_INVALIDARG)
805 return E_FAIL;
806 return hres;
809 default:
810 FIXME("unsupported vt: %d\n", V_VT(pvar));
811 return E_NOTIMPL;
815 static BOOL isemptyornull(const PROPVARIANT *propvar)
817 if (propvar->vt == VT_EMPTY || propvar->vt == VT_NULL)
818 return TRUE;
819 if ((propvar->vt & VT_ARRAY) == VT_ARRAY)
821 int i;
822 for (i=0; i<propvar->parray->cDims; i++)
824 if (propvar->parray->rgsabound[i].cElements != 0)
825 break;
827 return i == propvar->parray->cDims;
829 if (propvar->vt == VT_CLSID)
830 return !propvar->puuid;
832 if (propvar->vt & VT_VECTOR)
833 return !propvar->caub.cElems;
835 /* FIXME: byrefs, errors? */
836 return FALSE;
839 INT WINAPI PropVariantCompareEx(REFPROPVARIANT propvar1, REFPROPVARIANT propvar2,
840 PROPVAR_COMPARE_UNIT unit, PROPVAR_COMPARE_FLAGS flags)
842 const PROPVARIANT *propvar2_converted;
843 PROPVARIANT propvar2_static;
844 unsigned int count;
845 HRESULT hr;
846 INT res=-1;
848 TRACE("%p,%p,%x,%x\n", propvar1, propvar2, unit, flags);
850 if (isemptyornull(propvar1))
852 if (isemptyornull(propvar2))
853 return 0;
854 return (flags & PVCF_TREATEMPTYASGREATERTHAN) ? 1 : -1;
857 if (isemptyornull(propvar2))
858 return (flags & PVCF_TREATEMPTYASGREATERTHAN) ? -1 : 1;
860 if (propvar1->vt != propvar2->vt)
862 hr = PropVariantChangeType(&propvar2_static, propvar2, 0, propvar1->vt);
864 if (FAILED(hr))
865 return -1;
867 propvar2_converted = &propvar2_static;
869 else
870 propvar2_converted = propvar2;
872 #define CMP_NUM_VALUE(var) do { \
873 if (propvar1->var > propvar2_converted->var) \
874 res = 1; \
875 else if (propvar1->var < propvar2_converted->var) \
876 res = -1; \
877 else \
878 res = 0; \
879 } while (0)
881 switch (propvar1->vt)
883 case VT_I1:
884 CMP_NUM_VALUE(cVal);
885 break;
886 case VT_UI1:
887 CMP_NUM_VALUE(bVal);
888 break;
889 case VT_I2:
890 CMP_NUM_VALUE(iVal);
891 break;
892 case VT_UI2:
893 CMP_NUM_VALUE(uiVal);
894 break;
895 case VT_I4:
896 CMP_NUM_VALUE(lVal);
897 break;
898 case VT_UI4:
899 CMP_NUM_VALUE(ulVal);
900 break;
901 case VT_I8:
902 CMP_NUM_VALUE(hVal.QuadPart);
903 break;
904 case VT_UI8:
905 CMP_NUM_VALUE(uhVal.QuadPart);
906 break;
907 case VT_R4:
908 CMP_NUM_VALUE(fltVal);
909 break;
910 case VT_R8:
911 CMP_NUM_VALUE(dblVal);
912 break;
913 case VT_BSTR:
914 case VT_LPWSTR:
915 /* FIXME: Use other string flags. */
916 if (flags & (PVCF_USESTRCMPI | PVCF_USESTRCMPIC))
917 res = lstrcmpiW(propvar1->bstrVal, propvar2_converted->bstrVal);
918 else
919 res = lstrcmpW(propvar1->bstrVal, propvar2_converted->bstrVal);
920 break;
921 case VT_LPSTR:
922 /* FIXME: Use other string flags. */
923 if (flags & (PVCF_USESTRCMPI | PVCF_USESTRCMPIC))
924 res = lstrcmpiA(propvar1->pszVal, propvar2_converted->pszVal);
925 else
926 res = lstrcmpA(propvar1->pszVal, propvar2_converted->pszVal);
927 break;
928 case VT_CLSID:
929 res = memcmp(propvar1->puuid, propvar2->puuid, sizeof(*propvar1->puuid));
930 if (res) res = res > 0 ? 1 : -1;
931 break;
932 case VT_VECTOR | VT_UI1:
933 count = min(propvar1->caub.cElems, propvar2->caub.cElems);
934 res = count ? memcmp(propvar1->caub.pElems, propvar2->caub.pElems, sizeof(*propvar1->caub.pElems) * count) : 0;
935 if (res) res = res > 0 ? 1 : -1;
936 if (!res && propvar1->caub.cElems != propvar2->caub.cElems)
937 res = propvar1->caub.cElems > propvar2->caub.cElems ? 1 : -1;
938 break;
939 default:
940 FIXME("vartype %#x not handled\n", propvar1->vt);
941 res = -1;
942 break;
945 if (propvar2_converted == &propvar2_static)
946 PropVariantClear(&propvar2_static);
948 return res;