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
PROPVAR_ConvertFILETIME(const FILETIME * ft,PROPVARIANT * ppropvarDest,VARTYPE vt)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
PROPVAR_ConvertNumber(REFPROPVARIANT pv,int dest_bits,BOOL dest_signed,LONGLONG * res)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
PropVariantToDouble(REFPROPVARIANT propvarIn,double * ret)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
PropVariantToInt16(REFPROPVARIANT propvarIn,SHORT * ret)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
PropVariantToInt32(REFPROPVARIANT propvarIn,LONG * ret)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
PropVariantToInt64(REFPROPVARIANT propvarIn,LONGLONG * ret)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
PropVariantToUInt16(REFPROPVARIANT propvarIn,USHORT * ret)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
PropVariantToUInt32(REFPROPVARIANT propvarIn,ULONG * ret)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
PropVariantToUInt64(REFPROPVARIANT propvarIn,ULONGLONG * ret)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
PropVariantToBoolean(REFPROPVARIANT propvarIn,BOOL * ret)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
PropVariantToBuffer(REFPROPVARIANT propvarIn,void * ret,UINT cb)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
PropVariantToString(REFPROPVARIANT propvarIn,PWSTR ret,UINT cch)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
PropVariantToStringAlloc(REFPROPVARIANT propvarIn,WCHAR ** ret)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
PropVariantToStringWithDefault(REFPROPVARIANT propvarIn,LPCWSTR pszDefault)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 */
PropVariantChangeType(PROPVARIANT * ppropvarDest,REFPROPVARIANT propvarSrc,PROPVAR_CHANGE_FLAGS flags,VARTYPE vt)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
PROPVAR_GUIDToWSTR(REFGUID guid,WCHAR * str)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
InitPropVariantFromGUIDAsString(REFGUID guid,PROPVARIANT * ppropvar)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
InitVariantFromGUIDAsString(REFGUID guid,VARIANT * pvar)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
InitPropVariantFromBuffer(const VOID * pv,UINT cb,PROPVARIANT * ppropvar)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
InitPropVariantFromCLSID(REFCLSID clsid,PROPVARIANT * ppropvar)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
InitVariantFromBuffer(const VOID * pv,UINT cb,VARIANT * pvar)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
PROPVAR_HexToNum(const WCHAR * hex)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
PROPVAR_WCHARToGUID(const WCHAR * str,int len,GUID * guid)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
PropVariantToGUID(const PROPVARIANT * ppropvar,GUID * guid)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
VariantToGUID(const VARIANT * pvar,GUID * guid)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
isemptyornull(const PROPVARIANT * propvar)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
PropVariantCompareEx(REFPROPVARIANT propvar1,REFPROPVARIANT propvar2,PROPVAR_COMPARE_UNIT unit,PROPVAR_COMPARE_FLAGS flags)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