1 /*
2  * PropVariant Tests
3  *
4  * Copyright 2004 Robert Shearman
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 #include "windows.h"
22 #include "wtypes.h"
23 #include "ddeml.h"
24 
25 #include "wine/test.h"
26 
27 /* invalid in all versions */
28 #define PROP_INV 0x7f
29 /* valid in v0 and above (NT4+) */
30 #define PROP_V0  0
31 /* valid in v1 and above (Win2k+) */
32 #define PROP_V1  1
33 /* valid in v1a and above (WinXP+) */
34 #define PROP_V1A 2
35 #define PROP_TODO 0x80
36 
37 static const struct valid_mapping
38 {
39     BYTE simple;
40     BYTE with_array;
41     BYTE with_vector;
42     BYTE byref;
43 } valid_types[] =
44 {
45     { PROP_V0 , PROP_INV, PROP_INV, PROP_INV }, /* VT_EMPTY */
46     { PROP_V0 , PROP_INV, PROP_INV, PROP_INV }, /* VT_NULL */
47     { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO  }, /* VT_I2 */
48     { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO  }, /* VT_I4 */
49     { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO  }, /* VT_R4 */
50     { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO  }, /* VT_R8 */
51     { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO  }, /* VT_CY */
52     { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO  }, /* VT_DATE */
53     { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO  }, /* VT_BSTR */
54     { PROP_V1 , PROP_V1 | PROP_TODO , PROP_INV, PROP_V1 | PROP_TODO  }, /* VT_DISPATCH */
55     { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO  }, /* VT_ERROR */
56     { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO  }, /* VT_BOOL */
57     { PROP_V1 | PROP_TODO , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO  }, /* VT_VARIANT */
58     { PROP_V1 , PROP_V1 | PROP_TODO , PROP_INV, PROP_V1 | PROP_TODO  }, /* VT_UNKNOWN */
59     { PROP_V1 , PROP_V1 | PROP_TODO , PROP_INV, PROP_V1 | PROP_TODO  }, /* VT_DECIMAL */
60     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 15 */
61     { PROP_V1 , PROP_V1 | PROP_TODO , PROP_V1 , PROP_V1 | PROP_TODO  }, /* VT_I1 */
62     { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO  }, /* VT_UI1 */
63     { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO  }, /* VT_UI2 */
64     { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO  }, /* VT_UI4 */
65     { PROP_V0 , PROP_V1A | PROP_TODO, PROP_V0 , PROP_V1A | PROP_TODO }, /* VT_I8 */
66     { PROP_V0 , PROP_V1A | PROP_TODO, PROP_V0 , PROP_V1A | PROP_TODO }, /* VT_UI8 */
67     { PROP_V1 , PROP_V1 | PROP_TODO , PROP_INV, PROP_V1 | PROP_TODO  }, /* VT_INT */
68     { PROP_V1 , PROP_V1 | PROP_TODO , PROP_INV, PROP_V1 | PROP_TODO  }, /* VT_UINT */
69     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* VT_VOID */
70     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* VT_HRESULT */
71     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* VT_PTR */
72     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* VT_SAFEARRAY */
73     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* VT_CARRAY */
74     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* VT_USERDEFINED */
75     { PROP_V0 , PROP_INV, PROP_V0 , PROP_INV }, /* VT_LPSTR */
76     { PROP_V0 , PROP_INV, PROP_V0 , PROP_INV }, /* VT_LPWSTR */
77     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 32 */
78     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 33 */
79     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 34 */
80     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 35 */
81     { PROP_V1 | PROP_TODO , PROP_V1 | PROP_TODO , PROP_INV, PROP_V1 | PROP_TODO  }, /* VT_RECORD */
82     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* VT_INT_PTR */
83     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* VT_UINT_PTR */
84     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 39 */
85     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 40 */
86     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 41 */
87     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 42 */
88     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 43 */
89     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 44 */
90     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 45 */
91     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 46 */
92     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 47 */
93     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 48 */
94     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 49 */
95     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 50 */
96     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 51 */
97     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 52 */
98     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 53 */
99     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 54 */
100     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 55 */
101     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 56 */
102     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 57 */
103     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 58 */
104     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 59 */
105     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 60 */
106     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 61 */
107     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 62 */
108     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 63 */
109     { PROP_V0 , PROP_INV, PROP_V0 , PROP_INV }, /* VT_FILETIME */
110     { PROP_V0 , PROP_INV, PROP_INV, PROP_INV }, /* VT_BLOB */
111     { PROP_V0 , PROP_INV, PROP_INV, PROP_INV }, /* VT_STREAM */
112     { PROP_V0 , PROP_INV, PROP_INV, PROP_INV }, /* VT_STORAGE */
113     { PROP_V0 , PROP_INV, PROP_INV, PROP_INV }, /* VT_STREAMED_OBJECT */
114     { PROP_V0 , PROP_INV, PROP_INV, PROP_INV }, /* VT_STORED_OBJECT */
115     { PROP_V0 , PROP_INV, PROP_INV, PROP_INV }, /* VT_BLOB_OBJECT */
116     { PROP_V0 , PROP_INV, PROP_V0 , PROP_INV }  /* VT_CF */
117 };
118 
119 static const char* wine_vtypes[VT_CLSID+1] =
120 {
121   "VT_EMPTY","VT_NULL","VT_I2","VT_I4","VT_R4","VT_R8","VT_CY","VT_DATE",
122   "VT_BSTR","VT_DISPATCH","VT_ERROR","VT_BOOL","VT_VARIANT","VT_UNKNOWN",
123   "VT_DECIMAL","15","VT_I1","VT_UI1","VT_UI2","VT_UI4","VT_I8","VT_UI8",
124   "VT_INT","VT_UINT","VT_VOID","VT_HRESULT","VT_PTR","VT_SAFEARRAY",
125   "VT_CARRAY","VT_USERDEFINED","VT_LPSTR","VT_LPWSTR","32","33","34","35",
126   "VT_RECORD","VT_INT_PTR","VT_UINT_PTR","39","40","41","42","43","44","45",
127   "46","47","48","49","50","51","52","53","54","55","56","57","58","59","60",
128   "61","62","63","VT_FILETIME","VT_BLOB","VT_STREAM","VT_STORAGE",
129   "VT_STREAMED_OBJECT","VT_STORED_OBJECT","VT_BLOB_OBJECT","VT_CF","VT_CLSID"
130 };
131 
132 
133 static void expect(HRESULT hr, VARTYPE vt, BOOL copy, int line)
134 {
135     int idx = vt & VT_TYPEMASK;
136     BYTE flags;
137     const char *modifier;
138 
139     if(vt & VT_BYREF)
140     {
141         flags = valid_types[idx].byref;
142         modifier = "byref";
143     }
144     else if(vt & VT_ARRAY)
145     {
146         flags = valid_types[idx].with_array;
147         modifier = "array";
148     }
149     else if(vt & VT_VECTOR)
150     {
151         flags = valid_types[idx].with_vector;
152         modifier = "vector";
153     }
154     else
155     {
156         flags = valid_types[idx].simple;
157         modifier = "simple";
158     }
159 
160     if(flags == PROP_INV)
161     {
162         if (copy && (vt & VT_VECTOR))
163             ok(hr == DISP_E_BADVARTYPE || hr == STG_E_INVALIDPARAMETER, "%s (%s): got %08x (line %d)\n", wine_vtypes[idx], modifier, hr, line);
164         else
165             ok(hr == (copy ? DISP_E_BADVARTYPE : STG_E_INVALIDPARAMETER), "%s (%s): got %08x (line %d)\n", wine_vtypes[idx], modifier, hr, line);
166     }
167     else if(flags == PROP_V0)
168         ok(hr == S_OK, "%s (%s): got %08x\n", wine_vtypes[idx], modifier, hr);
169     else todo_wine_if(flags & PROP_TODO)
170     {
171         if(hr != S_OK)
172             win_skip("%s (%s): unsupported\n", wine_vtypes[idx], modifier);
173         else ok(hr == S_OK, "%s (%s): got %08x\n", wine_vtypes[idx], modifier, hr);
174     }
175 }
176 
177 static void test_validtypes(void)
178 {
179     PROPVARIANT propvar, copy, uninit;
180     HRESULT hr;
181     unsigned int i, ret;
182 
183     memset(&uninit, 0x77, sizeof(uninit));
184 
185     memset(&propvar, 0x55, sizeof(propvar));
186     hr = PropVariantClear(&propvar);
187     ok(hr == STG_E_INVALIDPARAMETER, "expected STG_E_INVALIDPARAMETER, got %08x\n", hr);
188     ok(propvar.vt == 0, "expected 0, got %d\n", propvar.vt);
189     ok(U(propvar).uhVal.QuadPart == 0, "expected 0, got %#x/%#x\n",
190        U(propvar).uhVal.u.LowPart, U(propvar).uhVal.u.HighPart);
191 
192     for (i = 0; i < sizeof(valid_types)/sizeof(valid_types[0]); i++)
193     {
194         VARTYPE vt;
195 
196         memset(&propvar, 0x55, sizeof(propvar));
197         if (i == VT_RECORD)
198             memset(&propvar, 0, sizeof(propvar));
199         else if (i == VT_BLOB || i == VT_BLOB_OBJECT)
200         {
201             U(propvar).blob.cbSize = 0;
202             U(propvar).blob.pBlobData = NULL;
203         }
204         else
205             U(propvar).pszVal = NULL;
206         vt = propvar.vt = i;
207         memset(&copy, 0x77, sizeof(copy));
208         hr = PropVariantCopy(&copy, &propvar);
209         expect(hr, vt, TRUE, __LINE__);
210         if (hr == S_OK)
211         {
212             ok(copy.vt == propvar.vt, "expected %d, got %d\n", propvar.vt, copy.vt);
213             ok(U(copy).uhVal.QuadPart == U(propvar).uhVal.QuadPart, "%u: expected %#x/%#x, got %#x/%#x\n",
214                i, U(propvar).uhVal.u.LowPart, U(propvar).uhVal.u.HighPart,
215                U(copy).uhVal.u.LowPart, U(copy).uhVal.u.HighPart);
216         }
217         else
218         {
219             ret = memcmp(&copy, &uninit, sizeof(copy));
220             ok(!ret || broken(ret) /* win2000 */, "%d: copy should stay unchanged\n", i);
221         }
222         hr = PropVariantClear(&propvar);
223         expect(hr, vt, FALSE, __LINE__);
224         ok(propvar.vt == 0, "expected 0, got %d\n", propvar.vt);
225         ok(U(propvar).uhVal.QuadPart == 0, "%u: expected 0, got %#x/%#x\n",
226            i, U(propvar).uhVal.u.LowPart, U(propvar).uhVal.u.HighPart);
227 
228         memset(&propvar, 0x55, sizeof(propvar));
229         U(propvar).pszVal = NULL;
230         vt = propvar.vt = i | VT_ARRAY;
231         memset(&copy, 0x77, sizeof(copy));
232         hr = PropVariantCopy(&copy, &propvar);
233         expect(hr, vt, TRUE, __LINE__);
234         if (hr == S_OK)
235         {
236             ok(copy.vt == propvar.vt, "expected %d, got %d\n", propvar.vt, copy.vt);
237             ok(U(copy).uhVal.QuadPart == 0, "%u: expected 0, got %#x/%#x\n",
238                i, U(copy).uhVal.u.LowPart, U(copy).uhVal.u.HighPart);
239         }
240         else
241         {
242             ret = memcmp(&copy, &uninit, sizeof(copy));
243             ok(!ret || broken(ret) /* win2000 */, "%d: copy should stay unchanged\n", i);
244         }
245         hr = PropVariantClear(&propvar);
246         expect(hr, vt, FALSE, __LINE__);
247         ok(propvar.vt == 0, "expected 0, got %d\n", propvar.vt);
248         ok(U(propvar).uhVal.QuadPart == 0, "%u: expected 0, got %#x/%#x\n",
249            i, U(propvar).uhVal.u.LowPart, U(propvar).uhVal.u.HighPart);
250 
251         memset(&propvar, 0x55, sizeof(propvar));
252         U(propvar).caub.cElems = 0;
253         U(propvar).caub.pElems = NULL;
254         vt = propvar.vt = i | VT_VECTOR;
255         memset(&copy, 0x77, sizeof(copy));
256         hr = PropVariantCopy(&copy, &propvar);
257         expect(hr, vt, TRUE, __LINE__);
258         if (hr == S_OK)
259         {
260             ok(copy.vt == propvar.vt, "expected %d, got %d\n", propvar.vt, copy.vt);
261             ok(!U(copy).caub.cElems, "%u: expected 0, got %d\n", i, U(copy).caub.cElems);
262             ok(!U(copy).caub.pElems, "%u: expected NULL, got %p\n", i, U(copy).caub.pElems);
263         }
264         else
265         {
266             ret = memcmp(&copy, &uninit, sizeof(copy));
267             ok(!ret || broken(ret) /* win2000 */, "%d: copy should stay unchanged\n", i);
268         }
269         hr = PropVariantClear(&propvar);
270         expect(hr, vt, FALSE, __LINE__);
271         ok(propvar.vt == 0, "expected 0, got %d\n", propvar.vt);
272         ok(U(propvar).uhVal.QuadPart == 0, "%u: expected 0, got %#x/%#x\n",
273            i, U(propvar).uhVal.u.LowPart, U(propvar).uhVal.u.HighPart);
274 
275         memset(&propvar, 0x55, sizeof(propvar));
276         U(propvar).pszVal = NULL;
277         vt = propvar.vt = i | VT_BYREF;
278         memset(&copy, 0x77, sizeof(copy));
279         hr = PropVariantCopy(&copy, &propvar);
280         expect(hr, vt, TRUE, __LINE__);
281         if (hr == S_OK)
282         {
283             ok(copy.vt == propvar.vt, "expected %d, got %d\n", propvar.vt, copy.vt);
284             ok(U(copy).uhVal.QuadPart == U(propvar).uhVal.QuadPart, "%u: expected %#x/%#x, got %#x/%#x\n",
285                i, U(propvar).uhVal.u.LowPart, U(propvar).uhVal.u.HighPart,
286                U(copy).uhVal.u.LowPart, U(copy).uhVal.u.HighPart);
287         }
288         else
289         {
290             ret = memcmp(&copy, &uninit, sizeof(copy));
291             ok(!ret || broken(ret) /* win2000 */, "%d: copy should stay unchanged\n", i);
292         }
293         hr = PropVariantClear(&propvar);
294         expect(hr, vt, FALSE, __LINE__);
295         ok(propvar.vt == 0, "expected 0, got %d\n", propvar.vt);
296         ok(U(propvar).uhVal.QuadPart == 0, "%u: expected 0, got %#x/%#x\n",
297            i, U(propvar).uhVal.u.LowPart, U(propvar).uhVal.u.HighPart);
298     }
299 }
300 
301 static void test_copy(void)
302 {
303     static char szTestString[] = "Test String";
304     static WCHAR wszTestString[] = {'T','e','s','t',' ','S','t','r','i','n','g',0};
305     PROPVARIANT propvarSrc;
306     PROPVARIANT propvarDst;
307     HRESULT hr;
308 
309     propvarSrc.vt = VT_BSTR;
310     U(propvarSrc).bstrVal = SysAllocString(wszTestString);
311 
312     hr = PropVariantCopy(&propvarDst, &propvarSrc);
313     ok(hr == S_OK, "PropVariantCopy(...VT_BSTR...) failed\n");
314     ok(!lstrcmpW(U(propvarSrc).bstrVal, U(propvarDst).bstrVal), "BSTR not copied properly\n");
315     hr = PropVariantClear(&propvarSrc);
316     ok(hr == S_OK, "PropVariantClear(...VT_BSTR...) failed\n");
317     hr = PropVariantClear(&propvarDst);
318     ok(hr == S_OK, "PropVariantClear(...VT_BSTR...) failed\n");
319 
320     propvarSrc.vt = VT_LPWSTR;
321     U(propvarSrc).pwszVal = wszTestString;
322     hr = PropVariantCopy(&propvarDst, &propvarSrc);
323     ok(hr == S_OK, "PropVariantCopy(...VT_LPWSTR...) failed\n");
324     ok(!lstrcmpW(U(propvarSrc).pwszVal, U(propvarDst).pwszVal), "Wide string not copied properly\n");
325     hr = PropVariantClear(&propvarDst);
326     ok(hr == S_OK, "PropVariantClear(...VT_LPWSTR...) failed\n");
327     memset(&propvarSrc, 0, sizeof(propvarSrc));
328 
329     propvarSrc.vt = VT_LPSTR;
330     U(propvarSrc).pszVal = szTestString;
331     hr = PropVariantCopy(&propvarDst, &propvarSrc);
332     ok(hr == S_OK, "PropVariantCopy(...VT_LPSTR...) failed\n");
333     ok(!strcmp(U(propvarSrc).pszVal, U(propvarDst).pszVal), "String not copied properly\n");
334     hr = PropVariantClear(&propvarDst);
335     ok(hr == S_OK, "PropVariantClear(...VT_LPSTR...) failed\n");
336     memset(&propvarSrc, 0, sizeof(propvarSrc));
337 }
338 
339 struct _PMemoryAllocator_vtable {
340     void *Allocate; /* virtual void* Allocate(ULONG cbSize); */
341     void *Free; /* virtual void Free(void *pv); */
342 };
343 
344 typedef struct _PMemoryAllocator {
345     struct _PMemoryAllocator_vtable *vt;
346 } PMemoryAllocator;
347 
348 static void * WINAPI PMemoryAllocator_Allocate(PMemoryAllocator *_this, ULONG cbSize)
349 {
350     return CoTaskMemAlloc(cbSize);
351 }
352 
353 static void WINAPI PMemoryAllocator_Free(PMemoryAllocator *_this, void *pv)
354 {
355     CoTaskMemFree(pv);
356 }
357 
358 #ifdef __i386__
359 
360 #include "pshpack1.h"
361 typedef struct
362 {
363     BYTE pop_eax;  /* popl  %eax  */
364     BYTE push_ecx; /* pushl %ecx  */
365     BYTE push_eax; /* pushl %eax  */
366     BYTE jmp_func; /* jmp   $func */
367     DWORD func;
368 } THISCALL_TO_STDCALL_THUNK;
369 #include "poppack.h"
370 
371 static THISCALL_TO_STDCALL_THUNK *wrapperCodeMem = NULL;
372 
373 static void fill_thunk(THISCALL_TO_STDCALL_THUNK *thunk, void *fn)
374 {
375     thunk->pop_eax = 0x58;
376     thunk->push_ecx = 0x51;
377     thunk->push_eax = 0x50;
378     thunk->jmp_func = 0xe9;
379     thunk->func = (char*)fn - (char*)(&thunk->func + 1);
380 }
381 
382 static void setup_vtable(struct _PMemoryAllocator_vtable *vtable)
383 {
384     wrapperCodeMem = VirtualAlloc(NULL, 2 * sizeof(*wrapperCodeMem),
385                                   MEM_COMMIT, PAGE_EXECUTE_READWRITE);
386 
387     fill_thunk(&wrapperCodeMem[0], PMemoryAllocator_Allocate);
388     fill_thunk(&wrapperCodeMem[1], PMemoryAllocator_Free);
389 
390     vtable->Allocate = &wrapperCodeMem[0];
391     vtable->Free = &wrapperCodeMem[1];
392 }
393 
394 #else
395 
396 static void setup_vtable(struct _PMemoryAllocator_vtable *vtable)
397 {
398     vtable->Allocate = PMemoryAllocator_Allocate;
399     vtable->Free = PMemoryAllocator_Free;
400 }
401 
402 #endif
403 
404 static const char serialized_empty[] = {
405     0,0, /* VT_EMPTY */
406     0,0, /* padding */
407 };
408 
409 static const char serialized_null[] = {
410     1,0, /* VT_NULL */
411     0,0, /* padding */
412 };
413 
414 static const char serialized_i4[] = {
415     3,0, /* VT_I4 */
416     0,0, /* padding */
417     0xef,0xcd,0xab,0xfe
418 };
419 
420 static const char serialized_bstr_wc[] = {
421     8,0, /* VT_BSTR */
422     0,0, /* padding */
423     10,0,0,0, /* size */
424     't',0,'e',0,
425     's',0,'t',0,
426     0,0,0,0
427 };
428 
429 static const char serialized_bstr_mb[] = {
430     8,0, /* VT_BSTR */
431     0,0, /* padding */
432     5,0,0,0, /* size */
433     't','e','s','t',
434     0,0,0,0
435 };
436 
437 static void test_propertytovariant(void)
438 {
439     HANDLE hole32;
440     BOOLEAN (__stdcall *pStgConvertPropertyToVariant)(const SERIALIZEDPROPERTYVALUE*,USHORT,PROPVARIANT*,PMemoryAllocator*);
441     PROPVARIANT propvar;
442     PMemoryAllocator allocator;
443     struct _PMemoryAllocator_vtable vtable;
444     BOOLEAN ret;
445     static const WCHAR test_string[] = {'t','e','s','t',0};
446 
447     hole32 = GetModuleHandleA("ole32");
448 
449     pStgConvertPropertyToVariant = (void*)GetProcAddress(hole32, "StgConvertPropertyToVariant");
450 
451     if (!pStgConvertPropertyToVariant)
452     {
453         win_skip("StgConvertPropertyToVariant not available\n");
454         return;
455     }
456 
457     setup_vtable(&vtable);
458     allocator.vt = &vtable;
459 
460     ret = pStgConvertPropertyToVariant((SERIALIZEDPROPERTYVALUE*)serialized_empty,
461         CP_WINUNICODE, &propvar, &allocator);
462 
463     ok(ret == 0, "StgConvertPropertyToVariant returned %i\n", ret);
464     ok(propvar.vt == VT_EMPTY, "unexpected vt %x\n", propvar.vt);
465 
466     ret = pStgConvertPropertyToVariant((SERIALIZEDPROPERTYVALUE*)serialized_null,
467         CP_WINUNICODE, &propvar, &allocator);
468 
469     ok(ret == 0, "StgConvertPropertyToVariant returned %i\n", ret);
470     ok(propvar.vt == VT_NULL, "unexpected vt %x\n", propvar.vt);
471 
472     ret = pStgConvertPropertyToVariant((SERIALIZEDPROPERTYVALUE*)serialized_i4,
473         CP_WINUNICODE, &propvar, &allocator);
474 
475     ok(ret == 0, "StgConvertPropertyToVariant returned %i\n", ret);
476     ok(propvar.vt == VT_I4, "unexpected vt %x\n", propvar.vt);
477     ok(U(propvar).lVal == 0xfeabcdef, "unexpected lVal %x\n", U(propvar).lVal);
478 
479     ret = pStgConvertPropertyToVariant((SERIALIZEDPROPERTYVALUE*)serialized_bstr_wc,
480         CP_WINUNICODE, &propvar, &allocator);
481 
482     ok(ret == 0, "StgConvertPropertyToVariant returned %i\n", ret);
483     ok(propvar.vt == VT_BSTR, "unexpected vt %x\n", propvar.vt);
484     ok(!lstrcmpW(U(propvar).bstrVal, test_string), "unexpected string value\n");
485     PropVariantClear(&propvar);
486 
487     ret = pStgConvertPropertyToVariant((SERIALIZEDPROPERTYVALUE*)serialized_bstr_mb,
488         CP_UTF8, &propvar, &allocator);
489 
490     ok(ret == 0, "StgConvertPropertyToVariant returned %i\n", ret);
491     ok(propvar.vt == VT_BSTR, "unexpected vt %x\n", propvar.vt);
492     ok(!lstrcmpW(U(propvar).bstrVal, test_string), "unexpected string value\n");
493     PropVariantClear(&propvar);
494 }
495 
496 static void test_varianttoproperty(void)
497 {
498     HANDLE hole32;
499     PROPVARIANT propvar;
500     SERIALIZEDPROPERTYVALUE *propvalue, *own_propvalue;
501     SERIALIZEDPROPERTYVALUE* (__stdcall *pStgConvertVariantToProperty)(
502         const PROPVARIANT*,USHORT,SERIALIZEDPROPERTYVALUE*,ULONG*,PROPID,BOOLEAN,ULONG*);
503     ULONG len;
504     static const WCHAR test_string[] = {'t','e','s','t',0};
505     BSTR test_string_bstr;
506 
507     hole32 = GetModuleHandleA("ole32");
508 
509     pStgConvertVariantToProperty = (void*)GetProcAddress(hole32, "StgConvertVariantToProperty");
510 
511     if (!pStgConvertVariantToProperty)
512     {
513         win_skip("StgConvertVariantToProperty not available\n");
514         return;
515     }
516 
517     own_propvalue = HeapAlloc(GetProcessHeap(), 0, sizeof(SERIALIZEDPROPERTYVALUE) + 20);
518 
519     PropVariantInit(&propvar);
520 
521     propvar.vt = VT_I4;
522     U(propvar).lVal = 0xfeabcdef;
523 
524     len = 0xdeadbeef;
525     propvalue = pStgConvertVariantToProperty(&propvar, CP_WINUNICODE, NULL, &len,
526         0, FALSE, 0);
527 
528     ok(propvalue == NULL, "got nonnull propvalue\n");
529     todo_wine ok(len == 8, "unexpected length %d\n", len);
530 
531     if (len == 0xdeadbeef)
532     {
533         HeapFree(GetProcessHeap(), 0, own_propvalue);
534         return;
535     }
536 
537     len = 20;
538     propvalue = pStgConvertVariantToProperty(&propvar, CP_WINUNICODE, own_propvalue, &len,
539         0, FALSE, 0);
540 
541     ok(propvalue == own_propvalue, "unexpected propvalue %p\n", propvalue);
542     ok(len == 8, "unexpected length %d\n", len);
543     ok(!memcmp(propvalue, serialized_i4, 8), "got wrong data\n");
544 
545     propvar.vt = VT_EMPTY;
546     len = 20;
547     own_propvalue->dwType = 0xdeadbeef;
548     propvalue = pStgConvertVariantToProperty(&propvar, CP_WINUNICODE, own_propvalue, &len,
549         0, FALSE, 0);
550 
551     ok(propvalue == own_propvalue, "unexpected propvalue %p\n", propvalue);
552     ok(len == 4 || broken(len == 0) /* before Vista */, "unexpected length %d\n", len);
553     if (len) ok(!memcmp(propvalue, serialized_empty, 4), "got wrong data\n");
554     else ok(propvalue->dwType == 0xdeadbeef, "unexpected type %d\n", propvalue->dwType);
555 
556     propvar.vt = VT_NULL;
557     len = 20;
558     propvalue = pStgConvertVariantToProperty(&propvar, CP_WINUNICODE, own_propvalue, &len,
559         0, FALSE, 0);
560 
561     ok(propvalue == own_propvalue, "unexpected propvalue %p\n", propvalue);
562     ok(len == 4, "unexpected length %d\n", len);
563     ok(!memcmp(propvalue, serialized_null, 4), "got wrong data\n");
564 
565     test_string_bstr = SysAllocString(test_string);
566 
567     propvar.vt = VT_BSTR;
568     U(propvar).bstrVal = test_string_bstr;
569     len = 20;
570     propvalue = pStgConvertVariantToProperty(&propvar, CP_WINUNICODE, own_propvalue, &len,
571         0, FALSE, 0);
572 
573     ok(propvalue == own_propvalue, "unexpected propvalue %p\n", propvalue);
574     ok(len == 20, "unexpected length %d\n", len);
575     ok(!memcmp(propvalue, serialized_bstr_wc, 20), "got wrong data\n");
576 
577     len = 20;
578     propvalue = pStgConvertVariantToProperty(&propvar, CP_UTF8, own_propvalue, &len,
579         0, FALSE, 0);
580 
581     ok(propvalue == own_propvalue, "unexpected propvalue %p\n", propvalue);
582     ok(len == 16, "unexpected length %d\n", len);
583     ok(!memcmp(propvalue, serialized_bstr_mb, 16), "got wrong data\n");
584 
585     SysFreeString(test_string_bstr);
586 
587     HeapFree(GetProcessHeap(), 0, own_propvalue);
588 }
589 
590 START_TEST(propvariant)
591 {
592     test_validtypes();
593     test_copy();
594     test_propertytovariant();
595     test_varianttoproperty();
596 }
597