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(©, 0x77, sizeof(copy)); 208 hr = PropVariantCopy(©, &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(©, &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(©, 0x77, sizeof(copy)); 232 hr = PropVariantCopy(©, &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(©, &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(©, 0x77, sizeof(copy)); 256 hr = PropVariantCopy(©, &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(©, &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(©, 0x77, sizeof(copy)); 279 hr = PropVariantCopy(©, &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(©, &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