makefiles: Don't use standard libs for programs that specify -nodefaultlibs.
[wine/zf.git] / dlls / propsys / propvar.c
blobdcfee2b0cc674c8b67ccbdafbb30ea55a3f77e54
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->u.pszVal = HeapAlloc(GetProcessHeap(), 0, 64);
51 if (!ppropvarDest->u.pszVal)
52 return E_OUTOFMEMORY;
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 );
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->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:
113 char *end;
114 *res = strtoll(pv->u.pszVal, &end, 0);
115 if (pv->u.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->u.pwszVal, &end, 0);
125 if (pv->u.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->u.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 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;
255 TRACE("%p,%p\n", propvarIn, ret);
257 *ret = FALSE;
259 switch (propvarIn->vt)
261 case VT_BOOL:
262 *ret = propvarIn->u.boolVal == VARIANT_TRUE;
263 return S_OK;
265 case VT_LPWSTR:
266 case VT_BSTR:
267 if (!propvarIn->u.pwszVal)
268 return DISP_E_TYPEMISMATCH;
270 if (!lstrcmpiW(propvarIn->u.pwszVal, trueW) || !lstrcmpW(propvarIn->u.pwszVal, true2W))
272 *ret = TRUE;
273 return S_OK;
276 if (!lstrcmpiW(propvarIn->u.pwszVal, falseW) || !lstrcmpW(propvarIn->u.pwszVal, false2W))
278 *ret = FALSE;
279 return S_OK;
281 break;
283 case VT_LPSTR:
284 if (!propvarIn->u.pszVal)
285 return DISP_E_TYPEMISMATCH;
287 if (!lstrcmpiA(propvarIn->u.pszVal, "true") || !lstrcmpA(propvarIn->u.pszVal, "#TRUE#"))
289 *ret = TRUE;
290 return S_OK;
293 if (!lstrcmpiA(propvarIn->u.pszVal, "false") || !lstrcmpA(propvarIn->u.pszVal, "#FALSE#"))
295 *ret = FALSE;
296 return S_OK;
298 break;
301 hr = PROPVAR_ConvertNumber(propvarIn, 64, TRUE, &res);
302 *ret = !!res;
303 return hr;
306 HRESULT WINAPI PropVariantToBuffer(REFPROPVARIANT propvarIn, void *ret, UINT cb)
308 HRESULT hr = S_OK;
310 TRACE("(%p, %p, %d)\n", propvarIn, ret, cb);
312 switch(propvarIn->vt)
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;
328 return hr;
332 HRESULT WINAPI PropVariantToString(REFPROPVARIANT propvarIn, PWSTR ret, UINT cch)
334 HRESULT hr;
335 WCHAR *stringW = NULL;
337 TRACE("(%p, %p, %d)\n", propvarIn, ret, cch);
339 ret[0] = '\0';
341 if(!cch)
342 return E_INVALIDARG;
344 hr = PropVariantToStringAlloc(propvarIn, &stringW);
345 if(SUCCEEDED(hr))
347 if(lstrlenW(stringW) >= cch)
348 hr = STRSAFE_E_INSUFFICIENT_BUFFER;
349 lstrcpynW(ret, stringW, cch);
350 CoTaskMemFree(stringW);
353 return hr;
356 HRESULT WINAPI PropVariantToStringAlloc(REFPROPVARIANT propvarIn, WCHAR **ret)
358 WCHAR *res = NULL;
359 HRESULT hr = S_OK;
361 TRACE("%p,%p semi-stub\n", propvarIn, ret);
363 switch(propvarIn->vt)
365 case VT_EMPTY:
366 case VT_NULL:
367 res = CoTaskMemAlloc(1*sizeof(WCHAR));
368 res[0] = '\0';
369 break;
371 case VT_LPSTR:
372 if(propvarIn->u.pszVal)
374 DWORD len;
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;
381 MultiByteToWideChar(CP_ACP, 0, propvarIn->u.pszVal, -1, res, len);
383 break;
385 case VT_LPWSTR:
386 case VT_BSTR:
387 if (propvarIn->u.pwszVal)
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);
394 break;
396 default:
397 FIXME("Unsupported conversion (%d)\n", propvarIn->vt);
398 hr = E_FAIL;
399 break;
402 *ret = res;
404 return hr;
407 PCWSTR WINAPI PropVariantToStringWithDefault(REFPROPVARIANT propvarIn, LPCWSTR pszDefault)
409 static const WCHAR str_empty[] = {0};
410 if (propvarIn->vt == VT_BSTR)
412 if (propvarIn->u.bstrVal == NULL)
413 return str_empty;
415 return propvarIn->u.bstrVal;
418 if (propvarIn->vt == VT_LPWSTR && propvarIn->u.pwszVal != NULL)
419 return propvarIn->u.pwszVal;
421 return pszDefault;
425 /******************************************************************
426 * PropVariantChangeType (PROPSYS.@)
428 HRESULT WINAPI PropVariantChangeType(PROPVARIANT *ppropvarDest, REFPROPVARIANT propvarSrc,
429 PROPVAR_CHANGE_FLAGS flags, VARTYPE vt)
431 HRESULT hr;
433 FIXME("(%p, %p, %d, %d, %d): semi-stub!\n", ppropvarDest, propvarSrc,
434 propvarSrc->vt, flags, vt);
436 if (vt == propvarSrc->vt)
437 return PropVariantCopy(ppropvarDest, propvarSrc);
439 if (propvarSrc->vt == VT_FILETIME)
440 return PROPVAR_ConvertFILETIME(&propvarSrc->u.filetime, ppropvarDest, vt);
442 switch (vt)
444 case VT_I1:
446 LONGLONG res;
448 hr = PROPVAR_ConvertNumber(propvarSrc, 8, TRUE, &res);
449 if (SUCCEEDED(hr))
451 ppropvarDest->vt = VT_I1;
452 ppropvarDest->u.cVal = (char)res;
454 return hr;
457 case VT_UI1:
459 LONGLONG res;
461 hr = PROPVAR_ConvertNumber(propvarSrc, 8, FALSE, &res);
462 if (SUCCEEDED(hr))
464 ppropvarDest->vt = VT_UI1;
465 ppropvarDest->u.bVal = (UCHAR)res;
467 return hr;
470 case VT_I2:
472 SHORT res;
473 hr = PropVariantToInt16(propvarSrc, &res);
474 if (SUCCEEDED(hr))
476 ppropvarDest->vt = VT_I2;
477 ppropvarDest->u.iVal = res;
479 return hr;
481 case VT_UI2:
483 USHORT res;
484 hr = PropVariantToUInt16(propvarSrc, &res);
485 if (SUCCEEDED(hr))
487 ppropvarDest->vt = VT_UI2;
488 ppropvarDest->u.uiVal = res;
490 return hr;
492 case VT_I4:
494 LONG res;
495 hr = PropVariantToInt32(propvarSrc, &res);
496 if (SUCCEEDED(hr))
498 ppropvarDest->vt = VT_I4;
499 ppropvarDest->u.lVal = res;
501 return hr;
503 case VT_UI4:
505 ULONG res;
506 hr = PropVariantToUInt32(propvarSrc, &res);
507 if (SUCCEEDED(hr))
509 ppropvarDest->vt = VT_UI4;
510 ppropvarDest->u.ulVal = res;
512 return hr;
514 case VT_I8:
516 LONGLONG res;
517 hr = PropVariantToInt64(propvarSrc, &res);
518 if (SUCCEEDED(hr))
520 ppropvarDest->vt = VT_I8;
521 ppropvarDest->u.hVal.QuadPart = res;
523 return hr;
525 case VT_UI8:
527 ULONGLONG res;
528 hr = PropVariantToUInt64(propvarSrc, &res);
529 if (SUCCEEDED(hr))
531 ppropvarDest->vt = VT_UI8;
532 ppropvarDest->u.uhVal.QuadPart = res;
534 return hr;
537 case VT_LPWSTR:
538 case VT_BSTR:
540 WCHAR *res;
541 hr = PropVariantToStringAlloc(propvarSrc, &res);
542 if (SUCCEEDED(hr))
544 ppropvarDest->vt = VT_LPWSTR;
545 ppropvarDest->u.pwszVal = res;
547 return hr;
550 case VT_LPSTR:
552 WCHAR *resW;
553 hr = PropVariantToStringAlloc(propvarSrc, &resW);
554 if (SUCCEEDED(hr))
556 char *res;
557 DWORD len;
559 len = WideCharToMultiByte(CP_ACP, 0, resW, -1, NULL, 0, NULL, NULL);
560 res = CoTaskMemAlloc(len);
561 if (res)
563 WideCharToMultiByte(CP_ACP, 0, resW, -1, res, len, NULL, NULL);
564 ppropvarDest->vt = VT_LPSTR;
565 ppropvarDest->u.pszVal = res;
567 else
568 hr = E_OUTOFMEMORY;
570 CoTaskMemFree(resW);
572 return hr;
575 default:
576 FIXME("Unhandled dest type: %d\n", vt);
577 return E_FAIL;
581 static void PROPVAR_GUIDToWSTR(REFGUID guid, WCHAR *str)
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};
587 swprintf(str, 39, 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]);
592 HRESULT WINAPI InitPropVariantFromGUIDAsString(REFGUID guid, PROPVARIANT *ppropvar)
594 TRACE("(%p %p)\n", guid, ppropvar);
596 if(!guid)
597 return E_FAIL;
599 ppropvar->vt = VT_LPWSTR;
600 ppropvar->u.pwszVal = CoTaskMemAlloc(39*sizeof(WCHAR));
601 if(!ppropvar->u.pwszVal)
602 return E_OUTOFMEMORY;
604 PROPVAR_GUIDToWSTR(guid, ppropvar->u.pwszVal);
605 return S_OK;
608 HRESULT WINAPI InitVariantFromGUIDAsString(REFGUID guid, VARIANT *pvar)
610 TRACE("(%p %p)\n", guid, pvar);
612 if(!guid) {
613 FIXME("guid == NULL\n");
614 return E_FAIL;
617 V_VT(pvar) = VT_BSTR;
618 V_BSTR(pvar) = SysAllocStringLen(NULL, 38);
619 if(!V_BSTR(pvar))
620 return E_OUTOFMEMORY;
622 PROPVAR_GUIDToWSTR(guid, V_BSTR(pvar));
623 return S_OK;
626 HRESULT WINAPI InitPropVariantFromBuffer(const VOID *pv, UINT cb, PROPVARIANT *ppropvar)
628 TRACE("(%p %u %p)\n", pv, cb, ppropvar);
630 ppropvar->u.caub.pElems = CoTaskMemAlloc(cb);
631 if(!ppropvar->u.caub.pElems)
632 return E_OUTOFMEMORY;
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;
640 HRESULT WINAPI InitPropVariantFromCLSID(REFCLSID clsid, PROPVARIANT *ppropvar)
642 TRACE("(%s %p)\n", debugstr_guid(clsid), ppropvar);
644 ppropvar->u.puuid = CoTaskMemAlloc(sizeof(*ppropvar->u.puuid));
645 if(!ppropvar->u.puuid)
646 return E_OUTOFMEMORY;
648 ppropvar->vt = VT_CLSID;
649 memcpy(ppropvar->u.puuid, clsid, sizeof(*ppropvar->u.puuid));
650 return S_OK;
653 HRESULT WINAPI InitVariantFromBuffer(const VOID *pv, UINT cb, VARIANT *pvar)
655 SAFEARRAY *arr;
656 void *data;
657 HRESULT hres;
659 TRACE("(%p %u %p)\n", pv, cb, pvar);
661 arr = SafeArrayCreateVector(VT_UI1, 0, cb);
662 if(!arr)
663 return E_OUTOFMEMORY;
665 hres = SafeArrayAccessData(arr, &data);
666 if(FAILED(hres)) {
667 SafeArrayDestroy(arr);
668 return hres;
671 memcpy(data, pv, cb);
673 hres = SafeArrayUnaccessData(arr);
674 if(FAILED(hres)) {
675 SafeArrayDestroy(arr);
676 return hres;
679 V_VT(pvar) = VT_ARRAY|VT_UI1;
680 V_ARRAY(pvar) = arr;
681 return S_OK;
684 static inline DWORD PROPVAR_HexToNum(const WCHAR *hex)
686 DWORD ret;
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;
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;
708 static inline HRESULT PROPVAR_WCHARToGUID(const WCHAR *str, int len, GUID *guid)
710 DWORD i, val=0;
711 const WCHAR *p;
713 memset(guid, 0, sizeof(GUID));
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;
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;
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;
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;
739 p++;
740 for(i=0; i<8 && val!=-1; i++) {
741 if(i == 2)
742 p++;
744 val = guid->Data4[i] = PROPVAR_HexToNum(p);
745 p += 2;
748 if(val == -1) {
749 WARN("Error parsing %s\n", debugstr_w(str));
750 memset(guid, 0, sizeof(GUID));
751 return E_INVALIDARG;
753 return S_OK;
756 HRESULT WINAPI PropVariantToGUID(const PROPVARIANT *ppropvar, GUID *guid)
758 TRACE("%p %p)\n", ppropvar, guid);
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;
769 default:
770 FIXME("unsupported vt: %d\n", ppropvar->vt);
771 return E_NOTIMPL;
775 HRESULT WINAPI VariantToGUID(const VARIANT *pvar, GUID *guid)
777 TRACE("(%p %p)\n", pvar, guid);
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;
787 default:
788 FIXME("unsupported vt: %d\n", V_VT(pvar));
789 return E_NOTIMPL;
793 static BOOL isemptyornull(const PROPVARIANT *propvar)
795 if (propvar->vt == VT_EMPTY || propvar->vt == VT_NULL)
796 return TRUE;
797 if ((propvar->vt & VT_ARRAY) == VT_ARRAY)
799 int i;
800 for (i=0; i<propvar->u.parray->cDims; i++)
802 if (propvar->u.parray->rgsabound[i].cElements != 0)
803 break;
805 return i == propvar->u.parray->cDims;
807 if (propvar->vt == VT_CLSID)
808 return !propvar->u.puuid;
810 /* FIXME: vectors, byrefs, errors? */
811 return FALSE;
814 INT WINAPI PropVariantCompareEx(REFPROPVARIANT propvar1, REFPROPVARIANT propvar2,
815 PROPVAR_COMPARE_UNIT unit, PROPVAR_COMPARE_FLAGS flags)
817 const PROPVARIANT *propvar2_converted;
818 PROPVARIANT propvar2_static;
819 HRESULT hr;
820 INT res=-1;
822 TRACE("%p,%p,%x,%x\n", propvar1, propvar2, unit, flags);
824 if (isemptyornull(propvar1))
826 if (isemptyornull(propvar2))
827 return 0;
828 return (flags & PVCF_TREATEMPTYASGREATERTHAN) ? 1 : -1;
831 if (isemptyornull(propvar2))
832 return (flags & PVCF_TREATEMPTYASGREATERTHAN) ? -1 : 1;
834 if (propvar1->vt != propvar2->vt)
836 hr = PropVariantChangeType(&propvar2_static, propvar2, 0, propvar1->vt);
838 if (FAILED(hr))
839 return -1;
841 propvar2_converted = &propvar2_static;
843 else
844 propvar2_converted = propvar2;
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)
855 switch (propvar1->vt)
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;
912 if (propvar2_converted == &propvar2_static)
913 PropVariantClear(&propvar2_static);
915 return res;