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