1 /* Unit test suite for SHLWAPI ordinal functions 2 * 3 * Copyright 2004 Jon Griffiths 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2.1 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 18 */ 19 20 #include <stdio.h> 21 22 #define COBJMACROS 23 #define CONST_VTABLE 24 #include "wine/test.h" 25 #include "winbase.h" 26 #include "winerror.h" 27 #include "winuser.h" 28 #include "ole2.h" 29 #include "oaidl.h" 30 #include "ocidl.h" 31 #include "mlang.h" 32 #include "shlwapi.h" 33 #include "docobj.h" 34 #include "shobjidl.h" 35 #include "shlobj.h" 36 37 /* Function ptrs for ordinal calls */ 38 static HMODULE hShlwapi; 39 40 static int (WINAPI *pSHSearchMapInt)(const int*,const int*,int,int); 41 static HRESULT (WINAPI *pGetAcceptLanguagesA)(LPSTR,LPDWORD); 42 43 static HANDLE (WINAPI *pSHAllocShared)(LPCVOID,DWORD,DWORD); 44 static LPVOID (WINAPI *pSHLockShared)(HANDLE,DWORD); 45 static BOOL (WINAPI *pSHUnlockShared)(LPVOID); 46 static BOOL (WINAPI *pSHFreeShared)(HANDLE,DWORD); 47 static HANDLE (WINAPI *pSHMapHandle)(HANDLE,DWORD,DWORD,DWORD,DWORD); 48 static HRESULT(WINAPIV *pSHPackDispParams)(DISPPARAMS*,VARIANTARG*,UINT,...); 49 static HRESULT(WINAPI *pIConnectionPoint_SimpleInvoke)(IConnectionPoint*,DISPID,DISPPARAMS*); 50 static HRESULT(WINAPI *pIConnectionPoint_InvokeWithCancel)(IConnectionPoint*,DISPID,DISPPARAMS*,DWORD,DWORD); 51 static HRESULT(WINAPI *pConnectToConnectionPoint)(IUnknown*,REFIID,BOOL,IUnknown*, LPDWORD,IConnectionPoint **); 52 static HRESULT(WINAPI *pSHPropertyBag_ReadLONG)(IPropertyBag *,LPCWSTR,LPLONG); 53 static LONG (WINAPI *pSHSetWindowBits)(HWND, INT, UINT, UINT); 54 static INT (WINAPI *pSHFormatDateTimeA)(const FILETIME UNALIGNED*, DWORD*, LPSTR, UINT); 55 static INT (WINAPI *pSHFormatDateTimeW)(const FILETIME UNALIGNED*, DWORD*, LPWSTR, UINT); 56 static DWORD (WINAPI *pSHGetObjectCompatFlags)(IUnknown*, const CLSID*); 57 static BOOL (WINAPI *pGUIDFromStringA)(LPSTR, CLSID *); 58 static HRESULT (WINAPI *pIUnknown_QueryServiceExec)(IUnknown*, REFIID, const GUID*, DWORD, DWORD, VARIANT*, VARIANT*); 59 static HRESULT (WINAPI *pIUnknown_ProfferService)(IUnknown*, REFGUID, IServiceProvider*, DWORD*); 60 static HWND (WINAPI *pSHCreateWorkerWindowA)(LONG, HWND, DWORD, DWORD, HMENU, LONG_PTR); 61 static HRESULT (WINAPI *pSHIShellFolder_EnumObjects)(LPSHELLFOLDER, HWND, SHCONTF, IEnumIDList**); 62 static DWORD (WINAPI *pSHGetIniStringW)(LPCWSTR, LPCWSTR, LPWSTR, DWORD, LPCWSTR); 63 static BOOL (WINAPI *pSHSetIniStringW)(LPCWSTR, LPCWSTR, LPCWSTR, LPCWSTR); 64 static HKEY (WINAPI *pSHGetShellKey)(DWORD, LPCWSTR, BOOL); 65 static HRESULT (WINAPI *pSKGetValueW)(DWORD, LPCWSTR, LPCWSTR, DWORD*, void*, DWORD*); 66 static HRESULT (WINAPI *pSKSetValueW)(DWORD, LPCWSTR, LPCWSTR, DWORD, void*, DWORD); 67 static HRESULT (WINAPI *pSKDeleteValueW)(DWORD, LPCWSTR, LPCWSTR); 68 static HRESULT (WINAPI *pSKAllocValueW)(DWORD, LPCWSTR, LPCWSTR, DWORD*, void**, DWORD*); 69 static HWND (WINAPI *pSHSetParentHwnd)(HWND, HWND); 70 static HRESULT (WINAPI *pIUnknown_GetClassID)(IUnknown*, CLSID*); 71 static HRESULT (WINAPI *pDllGetVersion)(DLLVERSIONINFO2*); 72 73 typedef struct SHELL_USER_SID { 74 SID_IDENTIFIER_AUTHORITY sidAuthority; 75 DWORD dwUserGroupID; 76 DWORD dwUserID; 77 } SHELL_USER_SID, *PSHELL_USER_SID; 78 typedef struct SHELL_USER_PERMISSION { 79 80 SHELL_USER_SID susID; 81 DWORD dwAccessType; 82 BOOL fInherit; 83 DWORD dwAccessMask; 84 DWORD dwInheritMask; 85 DWORD dwInheritAccessMask; 86 } SHELL_USER_PERMISSION, *PSHELL_USER_PERMISSION; 87 88 static SECURITY_DESCRIPTOR* (WINAPI *pGetShellSecurityDescriptor)(const SHELL_USER_PERMISSION**,int); 89 90 static const CHAR ie_international[] = { 91 'S','o','f','t','w','a','r','e','\\', 92 'M','i','c','r','o','s','o','f','t','\\', 93 'I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r','\\', 94 'I','n','t','e','r','n','a','t','i','o','n','a','l',0}; 95 static const CHAR acceptlanguage[] = { 96 'A','c','c','e','p','t','L','a','n','g','u','a','g','e',0}; 97 98 static int strcmp_wa(LPCWSTR strw, const char *stra) 99 { 100 CHAR buf[512]; 101 WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL); 102 return lstrcmpA(stra, buf); 103 } 104 105 typedef struct { 106 int id; 107 const void *args[5]; 108 } call_entry_t; 109 110 typedef struct { 111 call_entry_t *calls; 112 int count; 113 int alloc; 114 } call_trace_t; 115 116 static void init_call_trace(call_trace_t *ctrace) 117 { 118 ctrace->alloc = 10; 119 ctrace->count = 0; 120 ctrace->calls = HeapAlloc(GetProcessHeap(), 0, sizeof(call_entry_t) * ctrace->alloc); 121 } 122 123 static void free_call_trace(const call_trace_t *ctrace) 124 { 125 HeapFree(GetProcessHeap(), 0, ctrace->calls); 126 } 127 128 static void add_call(call_trace_t *ctrace, int id, const void *arg0, 129 const void *arg1, const void *arg2, const void *arg3, const void *arg4) 130 { 131 call_entry_t call; 132 133 call.id = id; 134 call.args[0] = arg0; 135 call.args[1] = arg1; 136 call.args[2] = arg2; 137 call.args[3] = arg3; 138 call.args[4] = arg4; 139 140 if (ctrace->count == ctrace->alloc) 141 { 142 ctrace->alloc *= 2; 143 ctrace->calls = HeapReAlloc(GetProcessHeap(),0, ctrace->calls, ctrace->alloc*sizeof(call_entry_t)); 144 } 145 146 ctrace->calls[ctrace->count++] = call; 147 } 148 149 static void ok_trace_(call_trace_t *texpected, call_trace_t *tgot, int line) 150 { 151 if (texpected->count == tgot->count) 152 { 153 INT i; 154 /* compare */ 155 for (i = 0; i < texpected->count; i++) 156 { 157 call_entry_t *expected = &texpected->calls[i]; 158 call_entry_t *got = &tgot->calls[i]; 159 INT j; 160 161 ok_(__FILE__, line)(expected->id == got->id, "got different ids %d: %d, %d\n", i+1, expected->id, got->id); 162 163 for (j = 0; j < 5; j++) 164 { 165 ok_(__FILE__, line)(expected->args[j] == got->args[j], "got different args[%d] for %d: %p, %p\n", j, i+1, 166 expected->args[j], got->args[j]); 167 } 168 } 169 } 170 else 171 ok_(__FILE__, line)(0, "traces length mismatch\n"); 172 } 173 174 #define ok_trace(a, b) ok_trace_(a, b, __LINE__) 175 176 /* trace of actually made calls */ 177 static call_trace_t trace_got; 178 179 static void test_GetAcceptLanguagesA(void) 180 { 181 static LPCSTR table[] = {"de,en-gb;q=0.7,en;q=0.3", 182 "de,en;q=0.3,en-gb;q=0.7", /* sorting is ignored */ 183 "winetest", /* content is ignored */ 184 "de-de,de;q=0.5", 185 "de", 186 NULL}; 187 188 DWORD exactsize; 189 char original[512]; 190 char language[32]; 191 char buffer[64]; 192 HKEY hroot = NULL; 193 LONG res_query = ERROR_SUCCESS; 194 LONG lres; 195 HRESULT hr; 196 DWORD maxlen = sizeof(buffer) - 2; 197 DWORD len; 198 LCID lcid; 199 LPCSTR entry; 200 INT i = 0; 201 202 lcid = GetUserDefaultLCID(); 203 204 /* Get the original Value */ 205 lres = RegOpenKeyA(HKEY_CURRENT_USER, ie_international, &hroot); 206 if (lres) { 207 skip("RegOpenKey(%s) failed: %d\n", ie_international, lres); 208 return; 209 } 210 len = sizeof(original); 211 original[0] = 0; 212 res_query = RegQueryValueExA(hroot, acceptlanguage, 0, NULL, (PBYTE)original, &len); 213 214 RegDeleteValueA(hroot, acceptlanguage); 215 216 /* Some windows versions use "lang-COUNTRY" as default */ 217 memset(language, 0, sizeof(language)); 218 len = GetLocaleInfoA(lcid, LOCALE_SISO639LANGNAME, language, sizeof(language)); 219 220 if (len) { 221 lstrcatA(language, "-"); 222 memset(buffer, 0, sizeof(buffer)); 223 len = GetLocaleInfoA(lcid, LOCALE_SISO3166CTRYNAME, buffer, sizeof(buffer) - len - 1); 224 lstrcatA(language, buffer); 225 } 226 else 227 { 228 /* LOCALE_SNAME has additional parts in some languages. Try only as last chance */ 229 memset(language, 0, sizeof(language)); 230 len = GetLocaleInfoA(lcid, LOCALE_SNAME, language, sizeof(language)); 231 } 232 233 /* get the default value */ 234 len = maxlen; 235 memset(buffer, '#', maxlen); 236 buffer[maxlen] = 0; 237 hr = pGetAcceptLanguagesA( buffer, &len); 238 239 if (hr != S_OK) { 240 win_skip("GetAcceptLanguagesA failed with 0x%x\n", hr); 241 goto restore_original; 242 } 243 244 if (lstrcmpA(buffer, language)) { 245 /* some windows versions use "lang" or "lang-country" as default */ 246 language[0] = 0; 247 hr = LcidToRfc1766A(lcid, language, sizeof(language)); 248 ok(hr == S_OK, "LcidToRfc1766A returned 0x%x and %s\n", hr, language); 249 } 250 251 ok(!lstrcmpA(buffer, language), 252 "have '%s' (searching for '%s')\n", language, buffer); 253 254 if (lstrcmpA(buffer, language)) { 255 win_skip("no more ideas, how to build the default language '%s'\n", buffer); 256 goto restore_original; 257 } 258 259 trace("detected default: %s\n", language); 260 while ((entry = table[i])) { 261 262 exactsize = lstrlenA(entry); 263 264 lres = RegSetValueExA(hroot, acceptlanguage, 0, REG_SZ, (const BYTE *) entry, exactsize + 1); 265 ok(!lres, "got %d for RegSetValueExA: %s\n", lres, entry); 266 267 /* len includes space for the terminating 0 before vista/w2k8 */ 268 len = exactsize + 2; 269 memset(buffer, '#', maxlen); 270 buffer[maxlen] = 0; 271 hr = pGetAcceptLanguagesA( buffer, &len); 272 ok(((hr == E_INVALIDARG) && (len == 0)) || 273 (SUCCEEDED(hr) && 274 ((len == exactsize) || (len == exactsize+1)) && 275 !lstrcmpA(buffer, entry)), 276 "+2_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer); 277 278 len = exactsize + 1; 279 memset(buffer, '#', maxlen); 280 buffer[maxlen] = 0; 281 hr = pGetAcceptLanguagesA( buffer, &len); 282 ok(((hr == E_INVALIDARG) && (len == 0)) || 283 (SUCCEEDED(hr) && 284 ((len == exactsize) || (len == exactsize+1)) && 285 !lstrcmpA(buffer, entry)), 286 "+1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer); 287 288 len = exactsize; 289 memset(buffer, '#', maxlen); 290 buffer[maxlen] = 0; 291 hr = pGetAcceptLanguagesA( buffer, &len); 292 293 /* There is no space for the string in the registry. 294 When the buffer is large enough, the default language is returned 295 296 When the buffer is too small for that fallback, win7_32 and w2k8_64 297 fail with E_NOT_SUFFICIENT_BUFFER, win8 fails with HRESULT_FROM_WIN32(ERROR_MORE_DATA), 298 other versions succeed and return a partial result while older os succeed 299 and overflow the buffer */ 300 301 ok(((hr == E_INVALIDARG) && (len == 0)) || 302 (((hr == S_OK) && !lstrcmpA(buffer, language) && (len == lstrlenA(language))) || 303 ((hr == S_OK) && !memcmp(buffer, language, len)) || 304 ((hr == E_NOT_SUFFICIENT_BUFFER) && !len) || 305 ((hr == __HRESULT_FROM_WIN32(ERROR_MORE_DATA)) && len == exactsize)), 306 "==_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer); 307 308 if (exactsize > 1) { 309 len = exactsize - 1; 310 memset(buffer, '#', maxlen); 311 buffer[maxlen] = 0; 312 hr = pGetAcceptLanguagesA( buffer, &len); 313 ok(((hr == E_INVALIDARG) && (len == 0)) || 314 (((hr == S_OK) && !lstrcmpA(buffer, language) && (len == lstrlenA(language))) || 315 ((hr == S_OK) && !memcmp(buffer, language, len)) || 316 ((hr == E_NOT_SUFFICIENT_BUFFER) && !len) || 317 ((hr == __HRESULT_FROM_WIN32(ERROR_MORE_DATA)) && len == exactsize - 1)), 318 "-1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer); 319 } 320 321 len = 1; 322 memset(buffer, '#', maxlen); 323 buffer[maxlen] = 0; 324 hr = pGetAcceptLanguagesA( buffer, &len); 325 ok(((hr == E_INVALIDARG) && (len == 0)) || 326 (((hr == S_OK) && !lstrcmpA(buffer, language) && (len == lstrlenA(language))) || 327 ((hr == S_OK) && !memcmp(buffer, language, len)) || 328 ((hr == E_NOT_SUFFICIENT_BUFFER) && !len) || 329 ((hr == __HRESULT_FROM_WIN32(ERROR_MORE_DATA)) && len == 1)), 330 "=1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer); 331 332 len = maxlen; 333 hr = pGetAcceptLanguagesA( NULL, &len); 334 335 /* w2k3 and below: E_FAIL and untouched len, 336 since w2k8: S_OK and needed size (excluding 0), win8 S_OK and size including 0. */ 337 ok( ((hr == S_OK) && ((len == exactsize) || (len == exactsize + 1))) || 338 ((hr == E_FAIL) && (len == maxlen)), 339 "NULL,max #%d: got 0x%x with %d and %s\n", i, hr, len, buffer); 340 341 i++; 342 } 343 344 /* without a value in the registry, a default language is returned */ 345 RegDeleteValueA(hroot, acceptlanguage); 346 347 len = maxlen; 348 memset(buffer, '#', maxlen); 349 buffer[maxlen] = 0; 350 hr = pGetAcceptLanguagesA( buffer, &len); 351 ok( ((hr == S_OK) && (len == lstrlenA(language))), 352 "max: got 0x%x with %d and %s (expected S_OK with %d and '%s'\n", 353 hr, len, buffer, lstrlenA(language), language); 354 355 len = 2; 356 memset(buffer, '#', maxlen); 357 buffer[maxlen] = 0; 358 hr = pGetAcceptLanguagesA( buffer, &len); 359 ok( (((hr == S_OK) || (hr == E_INVALIDARG)) && !memcmp(buffer, language, len)) || 360 ((hr == E_NOT_SUFFICIENT_BUFFER) && !len) || 361 ((hr == __HRESULT_FROM_WIN32(ERROR_CANNOT_COPY)) && !len), 362 "=2: got 0x%x with %d and %s\n", hr, len, buffer); 363 364 len = 1; 365 memset(buffer, '#', maxlen); 366 buffer[maxlen] = 0; 367 hr = pGetAcceptLanguagesA( buffer, &len); 368 /* When the buffer is too small, win7_32 and w2k8_64 and above fail with 369 E_NOT_SUFFICIENT_BUFFER, win8 ERROR_CANNOT_COPY, 370 other versions succeed and return a partial 0 terminated result while other versions 371 fail with E_INVALIDARG and return a partial unterminated result */ 372 ok( (((hr == S_OK) || (hr == E_INVALIDARG)) && !memcmp(buffer, language, len)) || 373 ((hr == E_NOT_SUFFICIENT_BUFFER) && !len) || 374 ((hr == __HRESULT_FROM_WIN32(ERROR_CANNOT_COPY)) && !len), 375 "=1: got 0x%x with %d and %s\n", hr, len, buffer); 376 377 len = 0; 378 memset(buffer, '#', maxlen); 379 buffer[maxlen] = 0; 380 hr = pGetAcceptLanguagesA( buffer, &len); 381 /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG, win8 ERROR_CANNOT_COPY */ 382 ok((hr == E_FAIL) || (hr == E_INVALIDARG) || (hr == __HRESULT_FROM_WIN32(ERROR_CANNOT_COPY)), 383 "got 0x%x\n", hr); 384 385 memset(buffer, '#', maxlen); 386 buffer[maxlen] = 0; 387 hr = pGetAcceptLanguagesA( buffer, NULL); 388 /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG */ 389 ok((hr == E_FAIL) || (hr == E_INVALIDARG), 390 "got 0x%x (expected E_FAIL or E_INVALIDARG)\n", hr); 391 392 393 hr = pGetAcceptLanguagesA( NULL, NULL); 394 /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG */ 395 ok((hr == E_FAIL) || (hr == E_INVALIDARG), 396 "got 0x%x (expected E_FAIL or E_INVALIDARG)\n", hr); 397 398 restore_original: 399 if (!res_query) { 400 len = lstrlenA(original); 401 lres = RegSetValueExA(hroot, acceptlanguage, 0, REG_SZ, (const BYTE *) original, len ? len + 1: 0); 402 ok(!lres, "RegSetValueEx(%s) failed: %d\n", original, lres); 403 } 404 else 405 { 406 RegDeleteValueA(hroot, acceptlanguage); 407 } 408 RegCloseKey(hroot); 409 } 410 411 static void test_SHSearchMapInt(void) 412 { 413 int keys[8], values[8]; 414 int i = 0; 415 416 if (!pSHSearchMapInt) 417 return; 418 419 memset(keys, 0, sizeof(keys)); 420 memset(values, 0, sizeof(values)); 421 keys[0] = 99; values[0] = 101; 422 423 /* NULL key/value lists crash native, so skip testing them */ 424 425 /* 1 element */ 426 i = pSHSearchMapInt(keys, values, 1, keys[0]); 427 ok(i == values[0], "Len 1, expected %d, got %d\n", values[0], i); 428 429 /* Key doesn't exist */ 430 i = pSHSearchMapInt(keys, values, 1, 100); 431 ok(i == -1, "Len 1 - bad key, expected -1, got %d\n", i); 432 433 /* Len = 0 => not found */ 434 i = pSHSearchMapInt(keys, values, 0, keys[0]); 435 ok(i == -1, "Len 1 - passed len 0, expected -1, got %d\n", i); 436 437 /* 2 elements, len = 1 */ 438 keys[1] = 98; values[1] = 102; 439 i = pSHSearchMapInt(keys, values, 1, keys[1]); 440 ok(i == -1, "Len 1 - array len 2, expected -1, got %d\n", i); 441 442 /* 2 elements, len = 2 */ 443 i = pSHSearchMapInt(keys, values, 2, keys[1]); 444 ok(i == values[1], "Len 2, expected %d, got %d\n", values[1], i); 445 446 /* Searches forward */ 447 keys[2] = 99; values[2] = 103; 448 i = pSHSearchMapInt(keys, values, 3, keys[0]); 449 ok(i == values[0], "Len 3, expected %d, got %d\n", values[0], i); 450 } 451 452 struct shared_struct 453 { 454 DWORD value; 455 HANDLE handle; 456 }; 457 458 static void test_alloc_shared(int argc, char **argv) 459 { 460 char cmdline[MAX_PATH]; 461 PROCESS_INFORMATION pi; 462 STARTUPINFOA si = { 0 }; 463 DWORD procid; 464 HANDLE hmem, hmem2 = 0; 465 struct shared_struct val, *p; 466 BOOL ret; 467 468 procid=GetCurrentProcessId(); 469 hmem=pSHAllocShared(NULL,10,procid); 470 ok(hmem!=NULL,"SHAllocShared(NULL...) failed: %u\n", GetLastError()); 471 ret = pSHFreeShared(hmem, procid); 472 ok( ret, "SHFreeShared failed: %u\n", GetLastError()); 473 474 val.value = 0x12345678; 475 val.handle = 0; 476 hmem = pSHAllocShared(&val, sizeof(val), procid); 477 ok(hmem!=NULL,"SHAllocShared(NULL...) failed: %u\n", GetLastError()); 478 479 p=pSHLockShared(hmem,procid); 480 ok(p!=NULL,"SHLockShared failed: %u\n", GetLastError()); 481 if (p!=NULL) 482 ok(p->value == 0x12345678, "Wrong value in shared memory: %d instead of %d\n", p->value, 0x12345678); 483 ret = pSHUnlockShared(p); 484 ok( ret, "SHUnlockShared failed: %u\n", GetLastError()); 485 486 sprintf(cmdline, "%s %s %d %p", argv[0], argv[1], procid, hmem); 487 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); 488 ok(ret, "could not create child process error: %u\n", GetLastError()); 489 if (ret) 490 { 491 winetest_wait_child_process(pi.hProcess); 492 CloseHandle(pi.hThread); 493 CloseHandle(pi.hProcess); 494 495 p = pSHLockShared(hmem, procid); 496 ok(p != NULL,"SHLockShared failed: %u\n", GetLastError()); 497 if (p != NULL && p->value != 0x12345678) 498 { 499 ok(p->value == 0x12345679, "Wrong value in shared memory: %d instead of %d\n", p->value, 0x12345679); 500 hmem2 = p->handle; 501 ok(hmem2 != NULL, "Expected handle in shared memory\n"); 502 } 503 ret = pSHUnlockShared(p); 504 ok(ret, "SHUnlockShared failed: %u\n", GetLastError()); 505 } 506 507 ret = pSHFreeShared(hmem, procid); 508 ok( ret, "SHFreeShared failed: %u\n", GetLastError()); 509 510 if (hmem2) 511 { 512 p = pSHLockShared(hmem2, procid); 513 ok(p != NULL,"SHLockShared failed: %u\n", GetLastError()); 514 if (p != NULL) 515 ok(p->value == 0xDEADBEEF, "Wrong value in shared memory: %d instead of %d\n", p->value, 0xDEADBEEF); 516 ret = pSHUnlockShared(p); 517 ok(ret, "SHUnlockShared failed: %u\n", GetLastError()); 518 519 ret = pSHFreeShared(hmem2, procid); 520 ok(ret, "SHFreeShared failed: %u\n", GetLastError()); 521 } 522 523 SetLastError(0xdeadbeef); 524 ret = pSHFreeShared(NULL, procid); 525 ok(ret, "SHFreeShared failed: %u\n", GetLastError()); 526 ok(GetLastError() == 0xdeadbeef, "last error should not have changed, got %u\n", GetLastError()); 527 } 528 529 static void test_alloc_shared_remote(DWORD procid, HANDLE hmem) 530 { 531 struct shared_struct val, *p; 532 HANDLE hmem2; 533 BOOL ret; 534 535 /* test directly accessing shared memory of a remote process */ 536 p = pSHLockShared(hmem, procid); 537 ok(p != NULL || broken(p == NULL) /* Windows 7/8 */, "SHLockShared failed: %u\n", GetLastError()); 538 if (p == NULL) 539 { 540 win_skip("Subprocess failed to modify shared memory, skipping test\n"); 541 return; 542 } 543 544 ok(p->value == 0x12345678, "Wrong value in shared memory: %d instead of %d\n", p->value, 0x12345678); 545 p->value++; 546 547 val.value = 0xDEADBEEF; 548 val.handle = 0; 549 p->handle = pSHAllocShared(&val, sizeof(val), procid); 550 ok(p->handle != NULL, "SHAllocShared failed: %u\n", GetLastError()); 551 552 ret = pSHUnlockShared(p); 553 ok(ret, "SHUnlockShared failed: %u\n", GetLastError()); 554 555 /* test SHMapHandle */ 556 SetLastError(0xdeadbeef); 557 hmem2 = pSHMapHandle(NULL, procid, GetCurrentProcessId(), 0, 0); 558 ok(hmem2 == NULL, "expected NULL, got new handle\n"); 559 ok(GetLastError() == 0xdeadbeef, "last error should not have changed, got %u\n", GetLastError()); 560 561 hmem2 = pSHMapHandle(hmem, procid, GetCurrentProcessId(), 0, 0); 562 563 /* It seems like Windows Vista/2008 uses a different internal implementation 564 * for shared memory, and calling SHMapHandle fails. */ 565 ok(hmem2 != NULL || broken(hmem2 == NULL), 566 "SHMapHandle failed: %u\n", GetLastError()); 567 if (hmem2 == NULL) 568 { 569 win_skip("Subprocess failed to map shared memory, skipping test\n"); 570 return; 571 } 572 573 p = pSHLockShared(hmem2, GetCurrentProcessId()); 574 ok(p != NULL, "SHLockShared failed: %u\n", GetLastError()); 575 576 if (p != NULL) 577 ok(p->value == 0x12345679, "Wrong value in shared memory: %d instead of %d\n", p->value, 0x12345679); 578 579 ret = pSHUnlockShared(p); 580 ok(ret, "SHUnlockShared failed: %u\n", GetLastError()); 581 582 ret = pSHFreeShared(hmem2, GetCurrentProcessId()); 583 ok(ret, "SHFreeShared failed: %u\n", GetLastError()); 584 } 585 586 static void test_fdsa(void) 587 { 588 typedef struct 589 { 590 DWORD num_items; /* Number of elements inserted */ 591 void *mem; /* Ptr to array */ 592 DWORD blocks_alloced; /* Number of elements allocated */ 593 BYTE inc; /* Number of elements to grow by when we need to expand */ 594 BYTE block_size; /* Size in bytes of an element */ 595 BYTE flags; /* Flags */ 596 } FDSA_info; 597 598 BOOL (WINAPI *pFDSA_Initialize)(DWORD block_size, DWORD inc, FDSA_info *info, void *mem, 599 DWORD init_blocks); 600 BOOL (WINAPI *pFDSA_Destroy)(FDSA_info *info); 601 DWORD (WINAPI *pFDSA_InsertItem)(FDSA_info *info, DWORD where, const void *block); 602 BOOL (WINAPI *pFDSA_DeleteItem)(FDSA_info *info, DWORD where); 603 604 FDSA_info info; 605 int block_size = 10, init_blocks = 4, inc = 2; 606 DWORD ret; 607 char *mem; 608 609 pFDSA_Initialize = (void *)GetProcAddress(hShlwapi, (LPSTR)208); 610 pFDSA_Destroy = (void *)GetProcAddress(hShlwapi, (LPSTR)209); 611 pFDSA_InsertItem = (void *)GetProcAddress(hShlwapi, (LPSTR)210); 612 pFDSA_DeleteItem = (void *)GetProcAddress(hShlwapi, (LPSTR)211); 613 614 mem = HeapAlloc(GetProcessHeap(), 0, block_size * init_blocks); 615 memset(&info, 0, sizeof(info)); 616 617 ok(pFDSA_Initialize(block_size, inc, &info, mem, init_blocks), "FDSA_Initialize rets FALSE\n"); 618 ok(info.num_items == 0, "num_items = %d\n", info.num_items); 619 ok(info.mem == mem, "mem = %p\n", info.mem); 620 ok(info.blocks_alloced == init_blocks, "blocks_alloced = %d\n", info.blocks_alloced); 621 ok(info.inc == inc, "inc = %d\n", info.inc); 622 ok(info.block_size == block_size, "block_size = %d\n", info.block_size); 623 ok(info.flags == 0, "flags = %d\n", info.flags); 624 625 ret = pFDSA_InsertItem(&info, 1234, "1234567890"); 626 ok(ret == 0, "ret = %d\n", ret); 627 ok(info.num_items == 1, "num_items = %d\n", info.num_items); 628 ok(info.mem == mem, "mem = %p\n", info.mem); 629 ok(info.blocks_alloced == init_blocks, "blocks_alloced = %d\n", info.blocks_alloced); 630 ok(info.inc == inc, "inc = %d\n", info.inc); 631 ok(info.block_size == block_size, "block_size = %d\n", info.block_size); 632 ok(info.flags == 0, "flags = %d\n", info.flags); 633 634 ret = pFDSA_InsertItem(&info, 1234, "abcdefghij"); 635 ok(ret == 1, "ret = %d\n", ret); 636 637 ret = pFDSA_InsertItem(&info, 1, "klmnopqrst"); 638 ok(ret == 1, "ret = %d\n", ret); 639 640 ret = pFDSA_InsertItem(&info, 0, "uvwxyzABCD"); 641 ok(ret == 0, "ret = %d\n", ret); 642 ok(info.mem == mem, "mem = %p\n", info.mem); 643 ok(info.flags == 0, "flags = %d\n", info.flags); 644 645 /* This next InsertItem will cause shlwapi to allocate its own mem buffer */ 646 ret = pFDSA_InsertItem(&info, 0, "EFGHIJKLMN"); 647 ok(ret == 0, "ret = %d\n", ret); 648 ok(info.mem != mem, "mem = %p\n", info.mem); 649 ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %d\n", info.blocks_alloced); 650 ok(info.flags == 0x1, "flags = %d\n", info.flags); 651 652 ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCD1234567890klmnopqrstabcdefghij", 50), "mem %s\n", (char*)info.mem); 653 654 ok(pFDSA_DeleteItem(&info, 2), "rets FALSE\n"); 655 ok(info.mem != mem, "mem = %p\n", info.mem); 656 ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %d\n", info.blocks_alloced); 657 ok(info.flags == 0x1, "flags = %d\n", info.flags); 658 659 ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCDklmnopqrstabcdefghij", 40), "mem %s\n", (char*)info.mem); 660 661 ok(pFDSA_DeleteItem(&info, 3), "rets FALSE\n"); 662 ok(info.mem != mem, "mem = %p\n", info.mem); 663 ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %d\n", info.blocks_alloced); 664 ok(info.flags == 0x1, "flags = %d\n", info.flags); 665 666 ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCDklmnopqrst", 30), "mem %s\n", (char*)info.mem); 667 668 ok(!pFDSA_DeleteItem(&info, 4), "does not ret FALSE\n"); 669 670 /* As shlwapi has allocated memory internally, Destroy will ret FALSE */ 671 ok(!pFDSA_Destroy(&info), "FDSA_Destroy does not ret FALSE\n"); 672 673 674 /* When Initialize is called with inc = 0, set it to 1 */ 675 ok(pFDSA_Initialize(block_size, 0, &info, mem, init_blocks), "FDSA_Initialize rets FALSE\n"); 676 ok(info.inc == 1, "inc = %d\n", info.inc); 677 678 /* This time, because shlwapi hasn't had to allocate memory 679 internally, Destroy rets non-zero */ 680 ok(pFDSA_Destroy(&info), "FDSA_Destroy rets FALSE\n"); 681 682 683 HeapFree(GetProcessHeap(), 0, mem); 684 } 685 686 static void test_GetShellSecurityDescriptor(void) 687 { 688 static const SHELL_USER_PERMISSION supCurrentUserFull = { 689 { {SECURITY_NULL_SID_AUTHORITY}, 0, 0 }, 690 ACCESS_ALLOWED_ACE_TYPE, FALSE, 691 GENERIC_ALL, 0, 0 }; 692 #define MY_INHERITANCE 0xBE /* invalid value to proof behavior */ 693 static const SHELL_USER_PERMISSION supEveryoneDenied = { 694 { {SECURITY_WORLD_SID_AUTHORITY}, SECURITY_WORLD_RID, 0 }, 695 ACCESS_DENIED_ACE_TYPE, TRUE, 696 GENERIC_WRITE, MY_INHERITANCE | 0xDEADBA00, GENERIC_READ }; 697 const SHELL_USER_PERMISSION* rgsup[2] = { 698 &supCurrentUserFull, &supEveryoneDenied, 699 }; 700 SECURITY_DESCRIPTOR* psd; 701 702 if(!pGetShellSecurityDescriptor) /* vista and later */ 703 { 704 win_skip("GetShellSecurityDescriptor not available\n"); 705 return; 706 } 707 708 psd = pGetShellSecurityDescriptor(NULL, 2); 709 ok(psd==NULL, "GetShellSecurityDescriptor should fail\n"); 710 psd = pGetShellSecurityDescriptor(rgsup, 0); 711 ok(psd==NULL, "GetShellSecurityDescriptor should fail, got %p\n", psd); 712 713 SetLastError(0xdeadbeef); 714 psd = pGetShellSecurityDescriptor(rgsup, 2); 715 ok(psd!=NULL, "GetShellSecurityDescriptor failed\n"); 716 if (psd!=NULL) 717 { 718 BOOL bHasDacl = FALSE, bDefaulted, ret; 719 PACL pAcl; 720 DWORD dwRev; 721 SECURITY_DESCRIPTOR_CONTROL control; 722 723 ok(IsValidSecurityDescriptor(psd), "returned value is not valid SD\n"); 724 725 ret = GetSecurityDescriptorControl(psd, &control, &dwRev); 726 ok(ret, "GetSecurityDescriptorControl failed with error %u\n", GetLastError()); 727 ok(0 == (control & SE_SELF_RELATIVE), "SD should be absolute\n"); 728 729 ret = GetSecurityDescriptorDacl(psd, &bHasDacl, &pAcl, &bDefaulted); 730 ok(ret, "GetSecurityDescriptorDacl failed with error %u\n", GetLastError()); 731 732 ok(bHasDacl, "SD has no DACL\n"); 733 if (bHasDacl) 734 { 735 ok(!bDefaulted, "DACL should not be defaulted\n"); 736 737 ok(pAcl != NULL, "NULL DACL!\n"); 738 if (pAcl != NULL) 739 { 740 ACL_SIZE_INFORMATION asiSize; 741 742 ok(IsValidAcl(pAcl), "DACL is not valid\n"); 743 744 ret = GetAclInformation(pAcl, &asiSize, sizeof(asiSize), AclSizeInformation); 745 ok(ret, "GetAclInformation failed with error %u\n", GetLastError()); 746 747 ok(asiSize.AceCount == 3, "Incorrect number of ACEs: %d entries\n", asiSize.AceCount); 748 if (asiSize.AceCount == 3) 749 { 750 ACCESS_ALLOWED_ACE *paaa; /* will use for DENIED too */ 751 752 ret = GetAce(pAcl, 0, (LPVOID*)&paaa); 753 ok(ret, "GetAce failed with error %u\n", GetLastError()); 754 ok(paaa->Header.AceType == ACCESS_ALLOWED_ACE_TYPE, 755 "Invalid ACE type %d\n", paaa->Header.AceType); 756 ok(paaa->Header.AceFlags == 0, "Invalid ACE flags %x\n", paaa->Header.AceFlags); 757 ok(paaa->Mask == GENERIC_ALL, "Invalid ACE mask %x\n", paaa->Mask); 758 759 ret = GetAce(pAcl, 1, (LPVOID*)&paaa); 760 ok(ret, "GetAce failed with error %u\n", GetLastError()); 761 ok(paaa->Header.AceType == ACCESS_DENIED_ACE_TYPE, 762 "Invalid ACE type %d\n", paaa->Header.AceType); 763 /* first one of two ACEs generated from inheritable entry - without inheritance */ 764 ok(paaa->Header.AceFlags == 0, "Invalid ACE flags %x\n", paaa->Header.AceFlags); 765 ok(paaa->Mask == GENERIC_WRITE, "Invalid ACE mask %x\n", paaa->Mask); 766 767 ret = GetAce(pAcl, 2, (LPVOID*)&paaa); 768 ok(ret, "GetAce failed with error %u\n", GetLastError()); 769 ok(paaa->Header.AceType == ACCESS_DENIED_ACE_TYPE, 770 "Invalid ACE type %d\n", paaa->Header.AceType); 771 /* second ACE - with inheritance */ 772 ok(paaa->Header.AceFlags == MY_INHERITANCE, 773 "Invalid ACE flags %x\n", paaa->Header.AceFlags); 774 ok(paaa->Mask == GENERIC_READ, "Invalid ACE mask %x\n", paaa->Mask); 775 } 776 } 777 } 778 779 LocalFree(psd); 780 } 781 } 782 783 static void test_SHPackDispParams(void) 784 { 785 DISPPARAMS params; 786 VARIANT vars[10]; 787 HRESULT hres; 788 789 memset(¶ms, 0xc0, sizeof(params)); 790 memset(vars, 0xc0, sizeof(vars)); 791 hres = pSHPackDispParams(¶ms, vars, 1, VT_I4, 0xdeadbeef); 792 ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres); 793 ok(params.cArgs == 1, "params.cArgs = %d\n", params.cArgs); 794 ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs); 795 ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs); 796 ok(params.rgvarg == vars, "params.rgvarg = %p\n", params.rgvarg); 797 ok(V_VT(vars) == VT_I4, "V_VT(var) = %d\n", V_VT(vars)); 798 ok(V_I4(vars) == 0xdeadbeef, "failed %x\n", V_I4(vars)); 799 800 memset(¶ms, 0xc0, sizeof(params)); 801 hres = pSHPackDispParams(¶ms, NULL, 0, 0); 802 ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres); 803 ok(params.cArgs == 0, "params.cArgs = %d\n", params.cArgs); 804 ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs); 805 ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs); 806 ok(params.rgvarg == NULL, "params.rgvarg = %p\n", params.rgvarg); 807 808 memset(vars, 0xc0, sizeof(vars)); 809 memset(¶ms, 0xc0, sizeof(params)); 810 hres = pSHPackDispParams(¶ms, vars, 4, VT_BSTR, (void*)0xdeadbeef, VT_EMPTY, 10, 811 VT_I4, 100, VT_DISPATCH, (void*)0xdeadbeef); 812 ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres); 813 ok(params.cArgs == 4, "params.cArgs = %d\n", params.cArgs); 814 ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs); 815 ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs); 816 ok(params.rgvarg == vars, "params.rgvarg = %p\n", params.rgvarg); 817 ok(V_VT(vars) == VT_DISPATCH, "V_VT(vars[0]) = %x\n", V_VT(vars)); 818 ok(V_I4(vars) == 0xdeadbeef, "V_I4(vars[0]) = %x\n", V_I4(vars)); 819 ok(V_VT(vars+1) == VT_I4, "V_VT(vars[1]) = %d\n", V_VT(vars+1)); 820 ok(V_I4(vars+1) == 100, "V_I4(vars[1]) = %x\n", V_I4(vars+1)); 821 ok(V_VT(vars+2) == VT_I4, "V_VT(vars[2]) = %d\n", V_VT(vars+2)); 822 ok(V_I4(vars+2) == 10, "V_I4(vars[2]) = %x\n", V_I4(vars+2)); 823 ok(V_VT(vars+3) == VT_BSTR, "V_VT(vars[3]) = %d\n", V_VT(vars+3)); 824 ok(V_BSTR(vars+3) == (void*)0xdeadbeef, "V_BSTR(vars[3]) = %p\n", V_BSTR(vars+3)); 825 } 826 827 typedef struct _disp 828 { 829 IDispatch IDispatch_iface; 830 LONG refCount; 831 } Disp; 832 833 static inline Disp *impl_from_IDispatch(IDispatch *iface) 834 { 835 return CONTAINING_RECORD(iface, Disp, IDispatch_iface); 836 } 837 838 typedef struct _contain 839 { 840 IConnectionPointContainer IConnectionPointContainer_iface; 841 LONG refCount; 842 843 UINT ptCount; 844 IConnectionPoint **pt; 845 } Contain; 846 847 static inline Contain *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface) 848 { 849 return CONTAINING_RECORD(iface, Contain, IConnectionPointContainer_iface); 850 } 851 852 typedef struct _cntptn 853 { 854 IConnectionPoint IConnectionPoint_iface; 855 LONG refCount; 856 857 Contain *container; 858 GUID id; 859 UINT sinkCount; 860 IUnknown **sink; 861 } ConPt; 862 863 static inline ConPt *impl_from_IConnectionPoint(IConnectionPoint *iface) 864 { 865 return CONTAINING_RECORD(iface, ConPt, IConnectionPoint_iface); 866 } 867 868 typedef struct _enum 869 { 870 IEnumConnections IEnumConnections_iface; 871 LONG refCount; 872 873 UINT idx; 874 ConPt *pt; 875 } EnumCon; 876 877 static inline EnumCon *impl_from_IEnumConnections(IEnumConnections *iface) 878 { 879 return CONTAINING_RECORD(iface, EnumCon, IEnumConnections_iface); 880 } 881 882 typedef struct _enumpt 883 { 884 IEnumConnectionPoints IEnumConnectionPoints_iface; 885 LONG refCount; 886 887 int idx; 888 Contain *container; 889 } EnumPt; 890 891 static inline EnumPt *impl_from_IEnumConnectionPoints(IEnumConnectionPoints *iface) 892 { 893 return CONTAINING_RECORD(iface, EnumPt, IEnumConnectionPoints_iface); 894 } 895 896 897 static HRESULT WINAPI Disp_QueryInterface( 898 IDispatch* This, 899 REFIID riid, 900 void **ppvObject) 901 { 902 *ppvObject = NULL; 903 904 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDispatch)) 905 { 906 *ppvObject = This; 907 } 908 909 if (*ppvObject) 910 { 911 IDispatch_AddRef(This); 912 return S_OK; 913 } 914 915 trace("no interface\n"); 916 return E_NOINTERFACE; 917 } 918 919 static ULONG WINAPI Disp_AddRef(IDispatch* This) 920 { 921 Disp *iface = impl_from_IDispatch(This); 922 return InterlockedIncrement(&iface->refCount); 923 } 924 925 static ULONG WINAPI Disp_Release(IDispatch* This) 926 { 927 Disp *iface = impl_from_IDispatch(This); 928 ULONG ret; 929 930 ret = InterlockedDecrement(&iface->refCount); 931 if (ret == 0) 932 HeapFree(GetProcessHeap(),0,This); 933 return ret; 934 } 935 936 static HRESULT WINAPI Disp_GetTypeInfoCount( 937 IDispatch* This, 938 UINT *pctinfo) 939 { 940 return ERROR_SUCCESS; 941 } 942 943 static HRESULT WINAPI Disp_GetTypeInfo( 944 IDispatch* This, 945 UINT iTInfo, 946 LCID lcid, 947 ITypeInfo **ppTInfo) 948 { 949 return ERROR_SUCCESS; 950 } 951 952 static HRESULT WINAPI Disp_GetIDsOfNames( 953 IDispatch* This, 954 REFIID riid, 955 LPOLESTR *rgszNames, 956 UINT cNames, 957 LCID lcid, 958 DISPID *rgDispId) 959 { 960 return ERROR_SUCCESS; 961 } 962 963 static HRESULT WINAPI Disp_Invoke( 964 IDispatch* This, 965 DISPID dispIdMember, 966 REFIID riid, 967 LCID lcid, 968 WORD wFlags, 969 DISPPARAMS *pDispParams, 970 VARIANT *pVarResult, 971 EXCEPINFO *pExcepInfo, 972 UINT *puArgErr) 973 { 974 trace("%p %x %s %x %x %p %p %p %p\n", This, dispIdMember, wine_dbgstr_guid(riid), lcid, wFlags, 975 pDispParams, pVarResult, pExcepInfo, puArgErr); 976 977 ok(dispIdMember == 0xa0 || dispIdMember == 0xa1, "Unknown dispIdMember\n"); 978 ok(pDispParams != NULL, "Invoked with NULL pDispParams\n"); 979 ok(wFlags == DISPATCH_METHOD, "Wrong flags %x\n",wFlags); 980 ok(lcid == 0,"Wrong lcid %x\n",lcid); 981 if (dispIdMember == 0xa0) 982 { 983 ok(pDispParams->cArgs == 0, "params.cArgs = %d\n", pDispParams->cArgs); 984 ok(pDispParams->cNamedArgs == 0, "params.cNamedArgs = %d\n", pDispParams->cArgs); 985 ok(pDispParams->rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", pDispParams->rgdispidNamedArgs); 986 ok(pDispParams->rgvarg == NULL, "params.rgvarg = %p\n", pDispParams->rgvarg); 987 } 988 else if (dispIdMember == 0xa1) 989 { 990 ok(pDispParams->cArgs == 2, "params.cArgs = %d\n", pDispParams->cArgs); 991 ok(pDispParams->cNamedArgs == 0, "params.cNamedArgs = %d\n", pDispParams->cArgs); 992 ok(pDispParams->rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", pDispParams->rgdispidNamedArgs); 993 ok(V_VT(pDispParams->rgvarg) == VT_BSTR, "V_VT(var) = %d\n", V_VT(pDispParams->rgvarg)); 994 ok(V_I4(pDispParams->rgvarg) == 0xdeadcafe , "failed %p\n", V_BSTR(pDispParams->rgvarg)); 995 ok(V_VT(pDispParams->rgvarg+1) == VT_I4, "V_VT(var) = %d\n", V_VT(pDispParams->rgvarg+1)); 996 ok(V_I4(pDispParams->rgvarg+1) == 0xdeadbeef, "failed %x\n", V_I4(pDispParams->rgvarg+1)); 997 } 998 999 return ERROR_SUCCESS; 1000 } 1001 1002 static const IDispatchVtbl disp_vtbl = { 1003 Disp_QueryInterface, 1004 Disp_AddRef, 1005 Disp_Release, 1006 1007 Disp_GetTypeInfoCount, 1008 Disp_GetTypeInfo, 1009 Disp_GetIDsOfNames, 1010 Disp_Invoke 1011 }; 1012 1013 static HRESULT WINAPI Enum_QueryInterface( 1014 IEnumConnections* This, 1015 REFIID riid, 1016 void **ppvObject) 1017 { 1018 *ppvObject = NULL; 1019 1020 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumConnections)) 1021 { 1022 *ppvObject = This; 1023 } 1024 1025 if (*ppvObject) 1026 { 1027 IEnumConnections_AddRef(This); 1028 return S_OK; 1029 } 1030 1031 trace("no interface\n"); 1032 return E_NOINTERFACE; 1033 } 1034 1035 static ULONG WINAPI Enum_AddRef(IEnumConnections* This) 1036 { 1037 EnumCon *iface = impl_from_IEnumConnections(This); 1038 return InterlockedIncrement(&iface->refCount); 1039 } 1040 1041 static ULONG WINAPI Enum_Release(IEnumConnections* This) 1042 { 1043 EnumCon *iface = impl_from_IEnumConnections(This); 1044 ULONG ret; 1045 1046 ret = InterlockedDecrement(&iface->refCount); 1047 if (ret == 0) 1048 HeapFree(GetProcessHeap(),0,This); 1049 return ret; 1050 } 1051 1052 static HRESULT WINAPI Enum_Next( 1053 IEnumConnections* This, 1054 ULONG cConnections, 1055 LPCONNECTDATA rgcd, 1056 ULONG *pcFetched) 1057 { 1058 EnumCon *iface = impl_from_IEnumConnections(This); 1059 1060 if (cConnections > 0 && iface->idx < iface->pt->sinkCount) 1061 { 1062 rgcd->pUnk = iface->pt->sink[iface->idx]; 1063 IUnknown_AddRef(iface->pt->sink[iface->idx]); 1064 rgcd->dwCookie=0xff; 1065 if (pcFetched) 1066 *pcFetched = 1; 1067 iface->idx++; 1068 return S_OK; 1069 } 1070 1071 return E_FAIL; 1072 } 1073 1074 static HRESULT WINAPI Enum_Skip( 1075 IEnumConnections* This, 1076 ULONG cConnections) 1077 { 1078 return E_FAIL; 1079 } 1080 1081 static HRESULT WINAPI Enum_Reset( 1082 IEnumConnections* This) 1083 { 1084 return E_FAIL; 1085 } 1086 1087 static HRESULT WINAPI Enum_Clone( 1088 IEnumConnections* This, 1089 IEnumConnections **ppEnum) 1090 { 1091 return E_FAIL; 1092 } 1093 1094 static const IEnumConnectionsVtbl enum_vtbl = { 1095 1096 Enum_QueryInterface, 1097 Enum_AddRef, 1098 Enum_Release, 1099 Enum_Next, 1100 Enum_Skip, 1101 Enum_Reset, 1102 Enum_Clone 1103 }; 1104 1105 static HRESULT WINAPI ConPt_QueryInterface( 1106 IConnectionPoint* This, 1107 REFIID riid, 1108 void **ppvObject) 1109 { 1110 *ppvObject = NULL; 1111 1112 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IConnectionPoint)) 1113 { 1114 *ppvObject = This; 1115 } 1116 1117 if (*ppvObject) 1118 { 1119 IConnectionPoint_AddRef(This); 1120 return S_OK; 1121 } 1122 1123 trace("no interface\n"); 1124 return E_NOINTERFACE; 1125 } 1126 1127 static ULONG WINAPI ConPt_AddRef( 1128 IConnectionPoint* This) 1129 { 1130 ConPt *iface = impl_from_IConnectionPoint(This); 1131 return InterlockedIncrement(&iface->refCount); 1132 } 1133 1134 static ULONG WINAPI ConPt_Release( 1135 IConnectionPoint* This) 1136 { 1137 ConPt *iface = impl_from_IConnectionPoint(This); 1138 ULONG ret; 1139 1140 ret = InterlockedDecrement(&iface->refCount); 1141 if (ret == 0) 1142 { 1143 if (iface->sinkCount > 0) 1144 { 1145 int i; 1146 for (i = 0; i < iface->sinkCount; i++) 1147 { 1148 if (iface->sink[i]) 1149 IUnknown_Release(iface->sink[i]); 1150 } 1151 HeapFree(GetProcessHeap(),0,iface->sink); 1152 } 1153 HeapFree(GetProcessHeap(),0,This); 1154 } 1155 return ret; 1156 } 1157 1158 static HRESULT WINAPI ConPt_GetConnectionInterface( 1159 IConnectionPoint* This, 1160 IID *pIID) 1161 { 1162 static int i = 0; 1163 ConPt *iface = impl_from_IConnectionPoint(This); 1164 if (i==0) 1165 { 1166 i++; 1167 return E_FAIL; 1168 } 1169 else 1170 memcpy(pIID,&iface->id,sizeof(GUID)); 1171 return S_OK; 1172 } 1173 1174 static HRESULT WINAPI ConPt_GetConnectionPointContainer( 1175 IConnectionPoint* This, 1176 IConnectionPointContainer **ppCPC) 1177 { 1178 ConPt *iface = impl_from_IConnectionPoint(This); 1179 1180 *ppCPC = &iface->container->IConnectionPointContainer_iface; 1181 return S_OK; 1182 } 1183 1184 static HRESULT WINAPI ConPt_Advise( 1185 IConnectionPoint* This, 1186 IUnknown *pUnkSink, 1187 DWORD *pdwCookie) 1188 { 1189 ConPt *iface = impl_from_IConnectionPoint(This); 1190 1191 if (iface->sinkCount == 0) 1192 iface->sink = HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown*)); 1193 else 1194 iface->sink = HeapReAlloc(GetProcessHeap(),0,iface->sink,sizeof(IUnknown*)*(iface->sinkCount+1)); 1195 iface->sink[iface->sinkCount] = pUnkSink; 1196 IUnknown_AddRef(pUnkSink); 1197 iface->sinkCount++; 1198 *pdwCookie = iface->sinkCount; 1199 return S_OK; 1200 } 1201 1202 static HRESULT WINAPI ConPt_Unadvise( 1203 IConnectionPoint* This, 1204 DWORD dwCookie) 1205 { 1206 ConPt *iface = impl_from_IConnectionPoint(This); 1207 1208 if (dwCookie > iface->sinkCount) 1209 return E_FAIL; 1210 else 1211 { 1212 IUnknown_Release(iface->sink[dwCookie-1]); 1213 iface->sink[dwCookie-1] = NULL; 1214 } 1215 return S_OK; 1216 } 1217 1218 static HRESULT WINAPI ConPt_EnumConnections( 1219 IConnectionPoint* This, 1220 IEnumConnections **ppEnum) 1221 { 1222 EnumCon *ec; 1223 1224 ec = HeapAlloc(GetProcessHeap(),0,sizeof(EnumCon)); 1225 ec->IEnumConnections_iface.lpVtbl = &enum_vtbl; 1226 ec->refCount = 1; 1227 ec->pt = impl_from_IConnectionPoint(This); 1228 ec->idx = 0; 1229 *ppEnum = &ec->IEnumConnections_iface; 1230 1231 return S_OK; 1232 } 1233 1234 static const IConnectionPointVtbl point_vtbl = { 1235 ConPt_QueryInterface, 1236 ConPt_AddRef, 1237 ConPt_Release, 1238 1239 ConPt_GetConnectionInterface, 1240 ConPt_GetConnectionPointContainer, 1241 ConPt_Advise, 1242 ConPt_Unadvise, 1243 ConPt_EnumConnections 1244 }; 1245 1246 static HRESULT WINAPI EnumPt_QueryInterface( 1247 IEnumConnectionPoints* This, 1248 REFIID riid, 1249 void **ppvObject) 1250 { 1251 *ppvObject = NULL; 1252 1253 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumConnectionPoints)) 1254 { 1255 *ppvObject = This; 1256 } 1257 1258 if (*ppvObject) 1259 { 1260 IEnumConnectionPoints_AddRef(This); 1261 return S_OK; 1262 } 1263 1264 trace("no interface\n"); 1265 return E_NOINTERFACE; 1266 } 1267 1268 static ULONG WINAPI EnumPt_AddRef(IEnumConnectionPoints* This) 1269 { 1270 EnumPt *iface = impl_from_IEnumConnectionPoints(This); 1271 return InterlockedIncrement(&iface->refCount); 1272 } 1273 1274 static ULONG WINAPI EnumPt_Release(IEnumConnectionPoints* This) 1275 { 1276 EnumPt *iface = impl_from_IEnumConnectionPoints(This); 1277 ULONG ret; 1278 1279 ret = InterlockedDecrement(&iface->refCount); 1280 if (ret == 0) 1281 HeapFree(GetProcessHeap(),0,This); 1282 return ret; 1283 } 1284 1285 static HRESULT WINAPI EnumPt_Next( 1286 IEnumConnectionPoints* This, 1287 ULONG cConnections, 1288 IConnectionPoint **rgcd, 1289 ULONG *pcFetched) 1290 { 1291 EnumPt *iface = impl_from_IEnumConnectionPoints(This); 1292 1293 if (cConnections > 0 && iface->idx < iface->container->ptCount) 1294 { 1295 *rgcd = iface->container->pt[iface->idx]; 1296 IConnectionPoint_AddRef(iface->container->pt[iface->idx]); 1297 if (pcFetched) 1298 *pcFetched = 1; 1299 iface->idx++; 1300 return S_OK; 1301 } 1302 1303 return E_FAIL; 1304 } 1305 1306 static HRESULT WINAPI EnumPt_Skip( 1307 IEnumConnectionPoints* This, 1308 ULONG cConnections) 1309 { 1310 return E_FAIL; 1311 } 1312 1313 static HRESULT WINAPI EnumPt_Reset( 1314 IEnumConnectionPoints* This) 1315 { 1316 return E_FAIL; 1317 } 1318 1319 static HRESULT WINAPI EnumPt_Clone( 1320 IEnumConnectionPoints* This, 1321 IEnumConnectionPoints **ppEnumPt) 1322 { 1323 return E_FAIL; 1324 } 1325 1326 static const IEnumConnectionPointsVtbl enumpt_vtbl = { 1327 1328 EnumPt_QueryInterface, 1329 EnumPt_AddRef, 1330 EnumPt_Release, 1331 EnumPt_Next, 1332 EnumPt_Skip, 1333 EnumPt_Reset, 1334 EnumPt_Clone 1335 }; 1336 1337 static HRESULT WINAPI Contain_QueryInterface( 1338 IConnectionPointContainer* This, 1339 REFIID riid, 1340 void **ppvObject) 1341 { 1342 *ppvObject = NULL; 1343 1344 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IConnectionPointContainer)) 1345 { 1346 *ppvObject = This; 1347 } 1348 1349 if (*ppvObject) 1350 { 1351 IConnectionPointContainer_AddRef(This); 1352 return S_OK; 1353 } 1354 1355 trace("no interface\n"); 1356 return E_NOINTERFACE; 1357 } 1358 1359 static ULONG WINAPI Contain_AddRef( 1360 IConnectionPointContainer* This) 1361 { 1362 Contain *iface = impl_from_IConnectionPointContainer(This); 1363 return InterlockedIncrement(&iface->refCount); 1364 } 1365 1366 static ULONG WINAPI Contain_Release( 1367 IConnectionPointContainer* This) 1368 { 1369 Contain *iface = impl_from_IConnectionPointContainer(This); 1370 ULONG ret; 1371 1372 ret = InterlockedDecrement(&iface->refCount); 1373 if (ret == 0) 1374 { 1375 if (iface->ptCount > 0) 1376 { 1377 int i; 1378 for (i = 0; i < iface->ptCount; i++) 1379 IConnectionPoint_Release(iface->pt[i]); 1380 HeapFree(GetProcessHeap(),0,iface->pt); 1381 } 1382 HeapFree(GetProcessHeap(),0,This); 1383 } 1384 return ret; 1385 } 1386 1387 static HRESULT WINAPI Contain_EnumConnectionPoints( 1388 IConnectionPointContainer* This, 1389 IEnumConnectionPoints **ppEnum) 1390 { 1391 EnumPt *ec; 1392 1393 ec = HeapAlloc(GetProcessHeap(),0,sizeof(EnumPt)); 1394 ec->IEnumConnectionPoints_iface.lpVtbl = &enumpt_vtbl; 1395 ec->refCount = 1; 1396 ec->idx= 0; 1397 ec->container = impl_from_IConnectionPointContainer(This); 1398 *ppEnum = &ec->IEnumConnectionPoints_iface; 1399 1400 return S_OK; 1401 } 1402 1403 static HRESULT WINAPI Contain_FindConnectionPoint( 1404 IConnectionPointContainer* This, 1405 REFIID riid, 1406 IConnectionPoint **ppCP) 1407 { 1408 Contain *iface = impl_from_IConnectionPointContainer(This); 1409 ConPt *pt; 1410 1411 if (!IsEqualIID(riid, &IID_NULL) || iface->ptCount ==0) 1412 { 1413 pt = HeapAlloc(GetProcessHeap(),0,sizeof(ConPt)); 1414 pt->IConnectionPoint_iface.lpVtbl = &point_vtbl; 1415 pt->refCount = 1; 1416 pt->sinkCount = 0; 1417 pt->sink = NULL; 1418 pt->container = iface; 1419 pt->id = IID_IDispatch; 1420 1421 if (iface->ptCount == 0) 1422 iface->pt =HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown*)); 1423 else 1424 iface->pt = HeapReAlloc(GetProcessHeap(),0,iface->pt,sizeof(IUnknown*)*(iface->ptCount+1)); 1425 iface->pt[iface->ptCount] = &pt->IConnectionPoint_iface; 1426 iface->ptCount++; 1427 1428 *ppCP = &pt->IConnectionPoint_iface; 1429 } 1430 else 1431 { 1432 *ppCP = iface->pt[0]; 1433 IUnknown_AddRef((IUnknown*)*ppCP); 1434 } 1435 1436 return S_OK; 1437 } 1438 1439 static const IConnectionPointContainerVtbl contain_vtbl = { 1440 Contain_QueryInterface, 1441 Contain_AddRef, 1442 Contain_Release, 1443 1444 Contain_EnumConnectionPoints, 1445 Contain_FindConnectionPoint 1446 }; 1447 1448 static void test_IConnectionPoint(void) 1449 { 1450 HRESULT rc; 1451 ULONG ref; 1452 IConnectionPoint *point; 1453 Contain *container; 1454 Disp *dispatch; 1455 DWORD cookie = 0xffffffff; 1456 DISPPARAMS params; 1457 VARIANT vars[10]; 1458 1459 container = HeapAlloc(GetProcessHeap(),0,sizeof(Contain)); 1460 container->IConnectionPointContainer_iface.lpVtbl = &contain_vtbl; 1461 container->refCount = 1; 1462 container->ptCount = 0; 1463 container->pt = NULL; 1464 1465 dispatch = HeapAlloc(GetProcessHeap(),0,sizeof(Disp)); 1466 dispatch->IDispatch_iface.lpVtbl = &disp_vtbl; 1467 dispatch->refCount = 1; 1468 1469 rc = pConnectToConnectionPoint((IUnknown*)dispatch, &IID_NULL, TRUE, (IUnknown*)container, &cookie, &point); 1470 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc); 1471 ok(point != NULL, "returned ConnectionPoint is NULL\n"); 1472 ok(cookie != 0xffffffff, "invalid cookie returned\n"); 1473 1474 rc = pIConnectionPoint_SimpleInvoke(point,0xa0,NULL); 1475 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc); 1476 1477 memset(¶ms, 0xc0, sizeof(params)); 1478 memset(vars, 0xc0, sizeof(vars)); 1479 rc = pSHPackDispParams(¶ms, vars, 2, VT_I4, 0xdeadbeef, VT_BSTR, 0xdeadcafe); 1480 ok(rc == S_OK, "SHPackDispParams failed: %08x\n", rc); 1481 1482 rc = pIConnectionPoint_SimpleInvoke(point,0xa1,¶ms); 1483 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc); 1484 1485 rc = pConnectToConnectionPoint(NULL, &IID_NULL, FALSE, (IUnknown*)container, &cookie, NULL); 1486 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc); 1487 1488 /* MSDN says this should be required but it crashs on XP 1489 IUnknown_Release(point); 1490 */ 1491 ref = IUnknown_Release((IUnknown*)container); 1492 ok(ref == 0, "leftover IConnectionPointContainer reference %i\n",ref); 1493 ref = IUnknown_Release((IUnknown*)dispatch); 1494 ok(ref == 0, "leftover IDispatch reference %i\n",ref); 1495 } 1496 1497 typedef struct _propbag 1498 { 1499 IPropertyBag IPropertyBag_iface; 1500 LONG refCount; 1501 1502 } PropBag; 1503 1504 static inline PropBag *impl_from_IPropertyBag(IPropertyBag *iface) 1505 { 1506 return CONTAINING_RECORD(iface, PropBag, IPropertyBag_iface); 1507 } 1508 1509 1510 static HRESULT WINAPI Prop_QueryInterface( 1511 IPropertyBag* This, 1512 REFIID riid, 1513 void **ppvObject) 1514 { 1515 *ppvObject = NULL; 1516 1517 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPropertyBag)) 1518 { 1519 *ppvObject = This; 1520 } 1521 1522 if (*ppvObject) 1523 { 1524 IPropertyBag_AddRef(This); 1525 return S_OK; 1526 } 1527 1528 trace("no interface\n"); 1529 return E_NOINTERFACE; 1530 } 1531 1532 static ULONG WINAPI Prop_AddRef( 1533 IPropertyBag* This) 1534 { 1535 PropBag *iface = impl_from_IPropertyBag(This); 1536 return InterlockedIncrement(&iface->refCount); 1537 } 1538 1539 static ULONG WINAPI Prop_Release( 1540 IPropertyBag* This) 1541 { 1542 PropBag *iface = impl_from_IPropertyBag(This); 1543 ULONG ret; 1544 1545 ret = InterlockedDecrement(&iface->refCount); 1546 if (ret == 0) 1547 HeapFree(GetProcessHeap(),0,This); 1548 return ret; 1549 } 1550 1551 static HRESULT WINAPI Prop_Read( 1552 IPropertyBag* This, 1553 LPCOLESTR pszPropName, 1554 VARIANT *pVar, 1555 IErrorLog *pErrorLog) 1556 { 1557 V_VT(pVar) = VT_BLOB|VT_BYREF; 1558 V_BYREF(pVar) = (LPVOID)0xdeadcafe; 1559 return S_OK; 1560 } 1561 1562 static HRESULT WINAPI Prop_Write( 1563 IPropertyBag* This, 1564 LPCOLESTR pszPropName, 1565 VARIANT *pVar) 1566 { 1567 return S_OK; 1568 } 1569 1570 1571 static const IPropertyBagVtbl prop_vtbl = { 1572 Prop_QueryInterface, 1573 Prop_AddRef, 1574 Prop_Release, 1575 1576 Prop_Read, 1577 Prop_Write 1578 }; 1579 1580 static void test_SHPropertyBag_ReadLONG(void) 1581 { 1582 PropBag *pb; 1583 HRESULT rc; 1584 LONG out; 1585 static const WCHAR szName1[] = {'n','a','m','e','1',0}; 1586 1587 pb = HeapAlloc(GetProcessHeap(),0,sizeof(PropBag)); 1588 pb->refCount = 1; 1589 pb->IPropertyBag_iface.lpVtbl = &prop_vtbl; 1590 1591 out = 0xfeedface; 1592 rc = pSHPropertyBag_ReadLONG(NULL, szName1, &out); 1593 ok(rc == E_INVALIDARG || broken(rc == S_OK), "incorrect return %x\n",rc); 1594 ok(out == 0xfeedface, "value should not have changed\n"); 1595 rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, NULL, &out); 1596 ok(rc == E_INVALIDARG || broken(rc == S_OK) || broken(rc == S_FALSE), "incorrect return %x\n",rc); 1597 ok(out == 0xfeedface, "value should not have changed\n"); 1598 rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, szName1, NULL); 1599 ok(rc == E_INVALIDARG || broken(rc == S_OK) || broken(rc == S_FALSE), "incorrect return %x\n",rc); 1600 rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, szName1, &out); 1601 ok(rc == DISP_E_BADVARTYPE || broken(rc == S_OK) || broken(rc == S_FALSE), "incorrect return %x\n",rc); 1602 ok(out == 0xfeedface || broken(out == 0xfeedfa00), "value should not have changed %x\n",out); 1603 IUnknown_Release((IUnknown*)pb); 1604 } 1605 1606 static void test_SHSetWindowBits(void) 1607 { 1608 HWND hwnd; 1609 DWORD style, styleold; 1610 WNDCLASSA clsA; 1611 1612 clsA.style = 0; 1613 clsA.lpfnWndProc = DefWindowProcA; 1614 clsA.cbClsExtra = 0; 1615 clsA.cbWndExtra = 0; 1616 clsA.hInstance = GetModuleHandleA(NULL); 1617 clsA.hIcon = 0; 1618 clsA.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); 1619 clsA.hbrBackground = NULL; 1620 clsA.lpszMenuName = NULL; 1621 clsA.lpszClassName = "Shlwapi test class"; 1622 RegisterClassA(&clsA); 1623 1624 hwnd = CreateWindowA("Shlwapi test class", "Test", WS_VISIBLE, 0, 0, 100, 100, 1625 NULL, NULL, GetModuleHandleA(NULL), 0); 1626 ok(IsWindow(hwnd), "failed to create window\n"); 1627 1628 /* null window */ 1629 SetLastError(0xdeadbeef); 1630 style = pSHSetWindowBits(NULL, GWL_STYLE, 0, 0); 1631 ok(style == 0, "expected 0 retval, got %d\n", style); 1632 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, 1633 "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError()); 1634 1635 /* zero mask, zero flags */ 1636 styleold = GetWindowLongA(hwnd, GWL_STYLE); 1637 style = pSHSetWindowBits(hwnd, GWL_STYLE, 0, 0); 1638 ok(styleold == style, "expected old style\n"); 1639 ok(styleold == GetWindowLongA(hwnd, GWL_STYLE), "expected to keep old style\n"); 1640 1641 /* test mask */ 1642 styleold = GetWindowLongA(hwnd, GWL_STYLE); 1643 ok(styleold & WS_VISIBLE, "expected WS_VISIBLE\n"); 1644 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0); 1645 1646 ok(style == styleold, "expected previous style, got %x\n", style); 1647 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n"); 1648 1649 /* test mask, unset style bit used */ 1650 styleold = GetWindowLongA(hwnd, GWL_STYLE); 1651 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0); 1652 ok(style == styleold, "expected previous style, got %x\n", style); 1653 ok(styleold == GetWindowLongA(hwnd, GWL_STYLE), "expected to keep old style\n"); 1654 1655 /* set back with flags */ 1656 styleold = GetWindowLongA(hwnd, GWL_STYLE); 1657 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, WS_VISIBLE); 1658 ok(style == styleold, "expected previous style, got %x\n", style); 1659 ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "expected updated style\n"); 1660 1661 /* reset and try to set without a mask */ 1662 pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0); 1663 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n"); 1664 styleold = GetWindowLongA(hwnd, GWL_STYLE); 1665 style = pSHSetWindowBits(hwnd, GWL_STYLE, 0, WS_VISIBLE); 1666 ok(style == styleold, "expected previous style, got %x\n", style); 1667 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n"); 1668 1669 DestroyWindow(hwnd); 1670 1671 UnregisterClassA("Shlwapi test class", GetModuleHandleA(NULL)); 1672 } 1673 1674 static void test_SHFormatDateTimeA(void) 1675 { 1676 FILETIME UNALIGNED filetime; 1677 CHAR buff[100], buff2[100], buff3[100]; 1678 SYSTEMTIME st; 1679 DWORD flags; 1680 INT ret; 1681 1682 if (0) 1683 { 1684 /* crashes on native */ 1685 pSHFormatDateTimeA(NULL, NULL, NULL, 0); 1686 } 1687 1688 GetLocalTime(&st); 1689 SystemTimeToFileTime(&st, &filetime); 1690 /* SHFormatDateTime expects input as utc */ 1691 LocalFileTimeToFileTime(&filetime, &filetime); 1692 1693 /* no way to get required buffer length here */ 1694 SetLastError(0xdeadbeef); 1695 ret = pSHFormatDateTimeA(&filetime, NULL, NULL, 0); 1696 ok(ret == 0, "got %d\n", ret); 1697 ok(GetLastError() == 0xdeadbeef || broken(GetLastError() == ERROR_SUCCESS /* Win7 */), 1698 "expected 0xdeadbeef, got %d\n", GetLastError()); 1699 1700 SetLastError(0xdeadbeef); 1701 buff[0] = 'a'; buff[1] = 0; 1702 ret = pSHFormatDateTimeA(&filetime, NULL, buff, 0); 1703 ok(ret == 0, "got %d\n", ret); 1704 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError()); 1705 ok(buff[0] == 'a', "expected same string, got %s\n", buff); 1706 1707 /* flags needs to have FDTF_NOAUTOREADINGORDER for these tests to succeed on Vista+ */ 1708 1709 /* all combinations documented as invalid succeeded */ 1710 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTTIME | FDTF_LONGTIME; 1711 SetLastError(0xdeadbeef); 1712 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff)); 1713 ok(ret == lstrlenA(buff)+1, "got %d\n", ret); 1714 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError()); 1715 1716 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_LONGDATE; 1717 SetLastError(0xdeadbeef); 1718 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff)); 1719 ok(ret == lstrlenA(buff)+1, "got %d\n", ret); 1720 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError()); 1721 1722 flags = FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE; 1723 SetLastError(0xdeadbeef); 1724 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff)); 1725 ok(ret == lstrlenA(buff)+1, "got %d\n", ret); 1726 ok(GetLastError() == 0xdeadbeef, 1727 "expected 0xdeadbeef, got %d\n", GetLastError()); 1728 1729 /* now check returned strings */ 1730 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTTIME; 1731 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff)); 1732 ok(ret == lstrlenA(buff)+1, "got %d\n", ret); 1733 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff2, sizeof(buff2)); 1734 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret); 1735 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff); 1736 1737 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGTIME; 1738 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff)); 1739 ok(ret == lstrlenA(buff)+1, "got %d\n", ret); 1740 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)); 1741 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret); 1742 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff); 1743 1744 /* both time flags */ 1745 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGTIME | FDTF_SHORTTIME; 1746 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff)); 1747 ok(ret == lstrlenA(buff)+1, "got %d\n", ret); 1748 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)); 1749 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret); 1750 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff); 1751 1752 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE; 1753 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff)); 1754 ok(ret == lstrlenA(buff)+1, "got %d\n", ret); 1755 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)); 1756 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret); 1757 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff); 1758 1759 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE; 1760 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff)); 1761 ok(ret == lstrlenA(buff)+1, "got %d\n", ret); 1762 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)); 1763 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret); 1764 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff); 1765 1766 /* both date flags */ 1767 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_SHORTDATE; 1768 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff)); 1769 ok(ret == lstrlenA(buff)+1, "got %d\n", ret); 1770 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)); 1771 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret); 1772 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff); 1773 1774 /* various combinations of date/time flags */ 1775 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_SHORTTIME; 1776 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff)); 1777 ok(ret == lstrlenA(buff)+1, "got %d, length %d\n", ret, lstrlenA(buff)+1); 1778 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)); 1779 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret); 1780 ok(lstrcmpA(buff3, buff + lstrlenA(buff) - lstrlenA(buff3)) == 0, 1781 "expected (%s), got (%s) for time part\n", 1782 buff3, buff + lstrlenA(buff) - lstrlenA(buff3)); 1783 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)); 1784 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret); 1785 buff[lstrlenA(buff2)] = '\0'; 1786 ok(lstrcmpA(buff2, buff) == 0, "expected (%s) got (%s) for date part\n", 1787 buff2, buff); 1788 1789 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_LONGTIME; 1790 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff)); 1791 ok(ret == lstrlenA(buff)+1, "got %d\n", ret); 1792 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)); 1793 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret); 1794 ok(lstrcmpA(buff3, buff + lstrlenA(buff) - lstrlenA(buff3)) == 0, 1795 "expected (%s), got (%s) for time part\n", 1796 buff3, buff + lstrlenA(buff) - lstrlenA(buff3)); 1797 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)); 1798 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret); 1799 buff[lstrlenA(buff2)] = '\0'; 1800 ok(lstrcmpA(buff2, buff) == 0, "expected (%s) got (%s) for date part\n", 1801 buff2, buff); 1802 1803 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_SHORTTIME; 1804 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff)); 1805 ok(ret == lstrlenA(buff)+1, "got %d\n", ret); 1806 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)); 1807 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret); 1808 strcat(buff2, " "); 1809 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)); 1810 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret); 1811 strcat(buff2, buff3); 1812 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff); 1813 1814 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_LONGTIME; 1815 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff)); 1816 ok(ret == lstrlenA(buff)+1, "got %d\n", ret); 1817 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)); 1818 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret); 1819 strcat(buff2, " "); 1820 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)); 1821 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret); 1822 strcat(buff2, buff3); 1823 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff); 1824 } 1825 1826 static void test_SHFormatDateTimeW(void) 1827 { 1828 FILETIME UNALIGNED filetime; 1829 WCHAR buff[100], buff2[100], buff3[100], *p1, *p2; 1830 SYSTEMTIME st; 1831 DWORD flags; 1832 INT ret; 1833 static const WCHAR spaceW[] = {' ',0}; 1834 #define UNICODE_LTR_MARK 0x200e 1835 #define UNICODE_RTL_MARK 0x200f 1836 1837 if (0) 1838 { 1839 /* crashes on native */ 1840 pSHFormatDateTimeW(NULL, NULL, NULL, 0); 1841 } 1842 1843 GetLocalTime(&st); 1844 SystemTimeToFileTime(&st, &filetime); 1845 /* SHFormatDateTime expects input as utc */ 1846 LocalFileTimeToFileTime(&filetime, &filetime); 1847 1848 /* no way to get required buffer length here */ 1849 SetLastError(0xdeadbeef); 1850 ret = pSHFormatDateTimeW(&filetime, NULL, NULL, 0); 1851 ok(ret == 0, "expected 0, got %d\n", ret); 1852 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError()); 1853 1854 SetLastError(0xdeadbeef); 1855 buff[0] = 'a'; buff[1] = 0; 1856 ret = pSHFormatDateTimeW(&filetime, NULL, buff, 0); 1857 ok(ret == 0, "expected 0, got %d\n", ret); 1858 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError()); 1859 ok(buff[0] == 'a', "expected same string\n"); 1860 1861 /* all combinations documented as invalid succeeded */ 1862 flags = FDTF_SHORTTIME | FDTF_LONGTIME; 1863 SetLastError(0xdeadbeef); 1864 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR)); 1865 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff), 1866 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret); 1867 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError()); 1868 1869 flags = FDTF_SHORTDATE | FDTF_LONGDATE; 1870 SetLastError(0xdeadbeef); 1871 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR)); 1872 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff), 1873 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret); 1874 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError()); 1875 1876 flags = FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE; 1877 SetLastError(0xdeadbeef); 1878 buff[0] = 0; /* NT4 doesn't clear the buffer on failure */ 1879 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR)); 1880 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff), 1881 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret); 1882 ok(GetLastError() == 0xdeadbeef, 1883 "expected 0xdeadbeef, got %d\n", GetLastError()); 1884 1885 /* now check returned strings */ 1886 flags = FDTF_SHORTTIME; 1887 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR)); 1888 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff), 1889 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret); 1890 SetLastError(0xdeadbeef); 1891 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR)); 1892 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret); 1893 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n"); 1894 1895 flags = FDTF_LONGTIME; 1896 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR)); 1897 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff), 1898 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret); 1899 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR)); 1900 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret); 1901 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n"); 1902 1903 /* both time flags */ 1904 flags = FDTF_LONGTIME | FDTF_SHORTTIME; 1905 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR)); 1906 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff), 1907 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret); 1908 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR)); 1909 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret); 1910 ok(lstrcmpW(buff, buff2) == 0, "expected equal string\n"); 1911 1912 flags = FDTF_SHORTDATE; 1913 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR)); 1914 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff), 1915 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret); 1916 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR)); 1917 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret); 1918 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n"); 1919 1920 flags = FDTF_LONGDATE; 1921 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR)); 1922 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff), 1923 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret); 1924 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR)); 1925 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret); 1926 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n"); 1927 1928 /* both date flags */ 1929 flags = FDTF_LONGDATE | FDTF_SHORTDATE; 1930 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR)); 1931 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff), 1932 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret); 1933 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR)); 1934 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret); 1935 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n"); 1936 1937 /* various combinations of date/time flags */ 1938 flags = FDTF_LONGDATE | FDTF_SHORTTIME; 1939 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR)); 1940 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff), 1941 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret); 1942 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR)); 1943 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret); 1944 ok(lstrcmpW(buff3, buff + lstrlenW(buff) - lstrlenW(buff3)) == 0, 1945 "expected (%s), got (%s) for time part\n", 1946 wine_dbgstr_w(buff3), wine_dbgstr_w(buff + lstrlenW(buff) - lstrlenW(buff3))); 1947 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR)); 1948 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret); 1949 p1 = buff; 1950 p2 = buff2; 1951 while (*p2 != '\0') 1952 { 1953 while (*p1 == UNICODE_LTR_MARK || *p1 == UNICODE_RTL_MARK) 1954 p1++; 1955 while (*p2 == UNICODE_LTR_MARK || *p2 == UNICODE_RTL_MARK) 1956 p2++; 1957 p1++; 1958 p2++; 1959 } 1960 *p1 = '\0'; 1961 ok(lstrcmpW(buff2, buff) == 0, "expected (%s) got (%s) for date part\n", 1962 wine_dbgstr_w(buff2), wine_dbgstr_w(buff)); 1963 1964 flags = FDTF_LONGDATE | FDTF_LONGTIME; 1965 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR)); 1966 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff), 1967 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret); 1968 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR)); 1969 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret); 1970 ok(lstrcmpW(buff3, buff + lstrlenW(buff) - lstrlenW(buff3)) == 0, 1971 "expected (%s), got (%s) for time part\n", 1972 wine_dbgstr_w(buff3), wine_dbgstr_w(buff + lstrlenW(buff) - lstrlenW(buff3))); 1973 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR)); 1974 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret); 1975 p1 = buff; 1976 p2 = buff2; 1977 while (*p2 != '\0') 1978 { 1979 while (*p1 == UNICODE_LTR_MARK || *p1 == UNICODE_RTL_MARK) 1980 p1++; 1981 while (*p2 == UNICODE_LTR_MARK || *p2 == UNICODE_RTL_MARK) 1982 p2++; 1983 p1++; 1984 p2++; 1985 } 1986 *p1 = '\0'; 1987 ok(lstrcmpW(buff2, buff) == 0, "expected (%s) got (%s) for date part\n", 1988 wine_dbgstr_w(buff2), wine_dbgstr_w(buff)); 1989 1990 flags = FDTF_SHORTDATE | FDTF_SHORTTIME; 1991 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR)); 1992 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff), 1993 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret); 1994 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR)); 1995 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret); 1996 lstrcatW(buff2, spaceW); 1997 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR)); 1998 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret); 1999 lstrcatW(buff2, buff3); 2000 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n"); 2001 2002 flags = FDTF_SHORTDATE | FDTF_LONGTIME; 2003 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR)); 2004 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff), 2005 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret); 2006 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR)); 2007 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret); 2008 lstrcatW(buff2, spaceW); 2009 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR)); 2010 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret); 2011 lstrcatW(buff2, buff3); 2012 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n"); 2013 } 2014 2015 static void test_SHGetObjectCompatFlags(void) 2016 { 2017 struct compat_value { 2018 CHAR nameA[30]; 2019 DWORD value; 2020 }; 2021 2022 struct compat_value values[] = { 2023 { "OTNEEDSSFCACHE", 0x1 }, 2024 { "NO_WEBVIEW", 0x2 }, 2025 { "UNBINDABLE", 0x4 }, 2026 { "PINDLL", 0x8 }, 2027 { "NEEDSFILESYSANCESTOR", 0x10 }, 2028 { "NOTAFILESYSTEM", 0x20 }, 2029 { "CTXMENU_NOVERBS", 0x40 }, 2030 { "CTXMENU_LIMITEDQI", 0x80 }, 2031 { "COCREATESHELLFOLDERONLY", 0x100 }, 2032 { "NEEDSSTORAGEANCESTOR", 0x200 }, 2033 { "NOLEGACYWEBVIEW", 0x400 }, 2034 { "CTXMENU_XPQCMFLAGS", 0x1000 }, 2035 { "NOIPROPERTYSTORE", 0x2000 } 2036 }; 2037 2038 static const char compat_path[] = "Software\\Microsoft\\Windows\\CurrentVersion\\ShellCompatibility\\Objects"; 2039 CHAR keyA[39]; /* {CLSID} */ 2040 HKEY root; 2041 DWORD ret; 2042 int i; 2043 2044 /* null args */ 2045 ret = pSHGetObjectCompatFlags(NULL, NULL); 2046 ok(ret == 0, "got %d\n", ret); 2047 2048 ret = RegOpenKeyA(HKEY_LOCAL_MACHINE, compat_path, &root); 2049 if (ret != ERROR_SUCCESS) 2050 { 2051 skip("No compatibility class data found\n"); 2052 return; 2053 } 2054 2055 for (i = 0; RegEnumKeyA(root, i, keyA, sizeof(keyA)) == ERROR_SUCCESS; i++) 2056 { 2057 HKEY clsid_key; 2058 2059 if (RegOpenKeyA(root, keyA, &clsid_key) == ERROR_SUCCESS) 2060 { 2061 CHAR valueA[30]; 2062 DWORD expected = 0, got, length = sizeof(valueA); 2063 CLSID clsid; 2064 int v; 2065 2066 for (v = 0; RegEnumValueA(clsid_key, v, valueA, &length, NULL, NULL, NULL, NULL) == ERROR_SUCCESS; v++) 2067 { 2068 int j; 2069 2070 for (j = 0; j < sizeof(values)/sizeof(struct compat_value); j++) 2071 if (lstrcmpA(values[j].nameA, valueA) == 0) 2072 { 2073 expected |= values[j].value; 2074 break; 2075 } 2076 2077 length = sizeof(valueA); 2078 } 2079 2080 pGUIDFromStringA(keyA, &clsid); 2081 got = pSHGetObjectCompatFlags(NULL, &clsid); 2082 ok(got == expected, "got 0x%08x, expected 0x%08x. Key %s\n", got, expected, keyA); 2083 2084 RegCloseKey(clsid_key); 2085 } 2086 } 2087 2088 RegCloseKey(root); 2089 } 2090 2091 typedef struct { 2092 IOleCommandTarget IOleCommandTarget_iface; 2093 LONG ref; 2094 } IOleCommandTargetImpl; 2095 2096 static inline IOleCommandTargetImpl *impl_from_IOleCommandTarget(IOleCommandTarget *iface) 2097 { 2098 return CONTAINING_RECORD(iface, IOleCommandTargetImpl, IOleCommandTarget_iface); 2099 } 2100 2101 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl; 2102 2103 static IOleCommandTarget* IOleCommandTargetImpl_Construct(void) 2104 { 2105 IOleCommandTargetImpl *obj; 2106 2107 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj)); 2108 obj->IOleCommandTarget_iface.lpVtbl = &IOleCommandTargetImpl_Vtbl; 2109 obj->ref = 1; 2110 2111 return &obj->IOleCommandTarget_iface; 2112 } 2113 2114 static HRESULT WINAPI IOleCommandTargetImpl_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppvObj) 2115 { 2116 IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface); 2117 2118 if (IsEqualIID(riid, &IID_IUnknown) || 2119 IsEqualIID(riid, &IID_IOleCommandTarget)) 2120 { 2121 *ppvObj = This; 2122 } 2123 2124 if(*ppvObj) 2125 { 2126 IOleCommandTarget_AddRef(iface); 2127 return S_OK; 2128 } 2129 2130 return E_NOINTERFACE; 2131 } 2132 2133 static ULONG WINAPI IOleCommandTargetImpl_AddRef(IOleCommandTarget *iface) 2134 { 2135 IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface); 2136 return InterlockedIncrement(&This->ref); 2137 } 2138 2139 static ULONG WINAPI IOleCommandTargetImpl_Release(IOleCommandTarget *iface) 2140 { 2141 IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface); 2142 ULONG ref = InterlockedDecrement(&This->ref); 2143 2144 if (!ref) 2145 { 2146 HeapFree(GetProcessHeap(), 0, This); 2147 return 0; 2148 } 2149 return ref; 2150 } 2151 2152 static HRESULT WINAPI IOleCommandTargetImpl_QueryStatus( 2153 IOleCommandTarget *iface, const GUID *group, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText) 2154 { 2155 return E_NOTIMPL; 2156 } 2157 2158 static HRESULT WINAPI IOleCommandTargetImpl_Exec( 2159 IOleCommandTarget *iface, 2160 const GUID *CmdGroup, 2161 DWORD nCmdID, 2162 DWORD nCmdexecopt, 2163 VARIANT *pvaIn, 2164 VARIANT *pvaOut) 2165 { 2166 add_call(&trace_got, 3, CmdGroup, (void*)(DWORD_PTR)nCmdID, (void*)(DWORD_PTR)nCmdexecopt, pvaIn, pvaOut); 2167 return S_OK; 2168 } 2169 2170 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl = 2171 { 2172 IOleCommandTargetImpl_QueryInterface, 2173 IOleCommandTargetImpl_AddRef, 2174 IOleCommandTargetImpl_Release, 2175 IOleCommandTargetImpl_QueryStatus, 2176 IOleCommandTargetImpl_Exec 2177 }; 2178 2179 typedef struct { 2180 IServiceProvider IServiceProvider_iface; 2181 LONG ref; 2182 } IServiceProviderImpl; 2183 2184 static inline IServiceProviderImpl *impl_from_IServiceProvider(IServiceProvider *iface) 2185 { 2186 return CONTAINING_RECORD(iface, IServiceProviderImpl, IServiceProvider_iface); 2187 } 2188 2189 typedef struct { 2190 IProfferService IProfferService_iface; 2191 LONG ref; 2192 } IProfferServiceImpl; 2193 2194 static inline IProfferServiceImpl *impl_from_IProfferService(IProfferService *iface) 2195 { 2196 return CONTAINING_RECORD(iface, IProfferServiceImpl, IProfferService_iface); 2197 } 2198 2199 2200 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl; 2201 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl; 2202 2203 static IServiceProvider* IServiceProviderImpl_Construct(void) 2204 { 2205 IServiceProviderImpl *obj; 2206 2207 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj)); 2208 obj->IServiceProvider_iface.lpVtbl = &IServiceProviderImpl_Vtbl; 2209 obj->ref = 1; 2210 2211 return &obj->IServiceProvider_iface; 2212 } 2213 2214 static IProfferService* IProfferServiceImpl_Construct(void) 2215 { 2216 IProfferServiceImpl *obj; 2217 2218 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj)); 2219 obj->IProfferService_iface.lpVtbl = &IProfferServiceImpl_Vtbl; 2220 obj->ref = 1; 2221 2222 return &obj->IProfferService_iface; 2223 } 2224 2225 static HRESULT WINAPI IServiceProviderImpl_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppvObj) 2226 { 2227 IServiceProviderImpl *This = impl_from_IServiceProvider(iface); 2228 2229 if (IsEqualIID(riid, &IID_IUnknown) || 2230 IsEqualIID(riid, &IID_IServiceProvider)) 2231 { 2232 *ppvObj = This; 2233 } 2234 2235 if(*ppvObj) 2236 { 2237 IServiceProvider_AddRef(iface); 2238 /* native uses redefined IID_IServiceProvider symbol, so we can't compare pointers */ 2239 if (IsEqualIID(riid, &IID_IServiceProvider)) 2240 add_call(&trace_got, 1, iface, &IID_IServiceProvider, 0, 0, 0); 2241 return S_OK; 2242 } 2243 2244 return E_NOINTERFACE; 2245 } 2246 2247 static ULONG WINAPI IServiceProviderImpl_AddRef(IServiceProvider *iface) 2248 { 2249 IServiceProviderImpl *This = impl_from_IServiceProvider(iface); 2250 return InterlockedIncrement(&This->ref); 2251 } 2252 2253 static ULONG WINAPI IServiceProviderImpl_Release(IServiceProvider *iface) 2254 { 2255 IServiceProviderImpl *This = impl_from_IServiceProvider(iface); 2256 ULONG ref = InterlockedDecrement(&This->ref); 2257 2258 if (!ref) 2259 { 2260 HeapFree(GetProcessHeap(), 0, This); 2261 return 0; 2262 } 2263 return ref; 2264 } 2265 2266 static HRESULT WINAPI IServiceProviderImpl_QueryService( 2267 IServiceProvider *iface, REFGUID service, REFIID riid, void **ppv) 2268 { 2269 /* native uses redefined pointer for IID_IOleCommandTarget, not one from uuid.lib */ 2270 if (IsEqualIID(riid, &IID_IOleCommandTarget)) 2271 { 2272 add_call(&trace_got, 2, iface, service, &IID_IOleCommandTarget, 0, 0); 2273 *ppv = IOleCommandTargetImpl_Construct(); 2274 } 2275 if (IsEqualIID(riid, &IID_IProfferService)) 2276 { 2277 if (IsEqualIID(service, &IID_IProfferService)) 2278 add_call(&trace_got, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0); 2279 *ppv = IProfferServiceImpl_Construct(); 2280 } 2281 return S_OK; 2282 } 2283 2284 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl = 2285 { 2286 IServiceProviderImpl_QueryInterface, 2287 IServiceProviderImpl_AddRef, 2288 IServiceProviderImpl_Release, 2289 IServiceProviderImpl_QueryService 2290 }; 2291 2292 static void test_IUnknown_QueryServiceExec(void) 2293 { 2294 IServiceProvider *provider; 2295 static const GUID dummy_serviceid = { 0xdeadbeef }; 2296 static const GUID dummy_groupid = { 0xbeefbeef }; 2297 call_trace_t trace_expected; 2298 HRESULT hr; 2299 2300 provider = IServiceProviderImpl_Construct(); 2301 2302 /* null source pointer */ 2303 hr = pIUnknown_QueryServiceExec(NULL, &dummy_serviceid, &dummy_groupid, 0, 0, 0, 0); 2304 ok(hr == E_FAIL || 2305 hr == E_NOTIMPL, /* win 8 */ 2306 "got 0x%08x\n", hr); 2307 2308 /* expected trace: 2309 IUnknown_QueryServiceExec( ptr1, serviceid, groupid, arg1, arg2, arg3, arg4); 2310 -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &prov ); 2311 -> IServiceProvider_QueryService( prov, serviceid, &IID_IOleCommandTarget, &obj ); 2312 -> IOleCommandTarget_Exec( obj, groupid, arg1, arg2, arg3, arg4 ); 2313 */ 2314 init_call_trace(&trace_expected); 2315 2316 add_call(&trace_expected, 1, provider, &IID_IServiceProvider, 0, 0, 0); 2317 add_call(&trace_expected, 2, provider, &dummy_serviceid, &IID_IOleCommandTarget, 0, 0); 2318 add_call(&trace_expected, 3, &dummy_groupid, (void*)0x1, (void*)0x2, (void*)0x3, (void*)0x4); 2319 2320 init_call_trace(&trace_got); 2321 hr = pIUnknown_QueryServiceExec((IUnknown*)provider, &dummy_serviceid, &dummy_groupid, 0x1, 0x2, (void*)0x3, (void*)0x4); 2322 ok(hr == S_OK, "got 0x%08x\n", hr); 2323 2324 ok_trace(&trace_expected, &trace_got); 2325 2326 free_call_trace(&trace_expected); 2327 free_call_trace(&trace_got); 2328 2329 IServiceProvider_Release(provider); 2330 } 2331 2332 2333 static HRESULT WINAPI IProfferServiceImpl_QueryInterface(IProfferService *iface, REFIID riid, void **ppvObj) 2334 { 2335 IProfferServiceImpl *This = impl_from_IProfferService(iface); 2336 2337 if (IsEqualIID(riid, &IID_IUnknown) || 2338 IsEqualIID(riid, &IID_IProfferService)) 2339 { 2340 *ppvObj = This; 2341 } 2342 else if (IsEqualIID(riid, &IID_IServiceProvider)) 2343 { 2344 *ppvObj = IServiceProviderImpl_Construct(); 2345 add_call(&trace_got, 1, iface, &IID_IServiceProvider, 0, 0, 0); 2346 return S_OK; 2347 } 2348 2349 if(*ppvObj) 2350 { 2351 IProfferService_AddRef(iface); 2352 return S_OK; 2353 } 2354 2355 return E_NOINTERFACE; 2356 } 2357 2358 static ULONG WINAPI IProfferServiceImpl_AddRef(IProfferService *iface) 2359 { 2360 IProfferServiceImpl *This = impl_from_IProfferService(iface); 2361 return InterlockedIncrement(&This->ref); 2362 } 2363 2364 static ULONG WINAPI IProfferServiceImpl_Release(IProfferService *iface) 2365 { 2366 IProfferServiceImpl *This = impl_from_IProfferService(iface); 2367 ULONG ref = InterlockedDecrement(&This->ref); 2368 2369 if (!ref) 2370 { 2371 HeapFree(GetProcessHeap(), 0, This); 2372 return 0; 2373 } 2374 return ref; 2375 } 2376 2377 static HRESULT WINAPI IProfferServiceImpl_ProfferService(IProfferService *iface, 2378 REFGUID service, IServiceProvider *pService, DWORD *pCookie) 2379 { 2380 *pCookie = 0xdeadbeef; 2381 add_call(&trace_got, 3, service, pService, pCookie, 0, 0); 2382 return S_OK; 2383 } 2384 2385 static HRESULT WINAPI IProfferServiceImpl_RevokeService(IProfferService *iface, DWORD cookie) 2386 { 2387 add_call(&trace_got, 4, (void*)(DWORD_PTR)cookie, 0, 0, 0, 0); 2388 return S_OK; 2389 } 2390 2391 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl = 2392 { 2393 IProfferServiceImpl_QueryInterface, 2394 IProfferServiceImpl_AddRef, 2395 IProfferServiceImpl_Release, 2396 IProfferServiceImpl_ProfferService, 2397 IProfferServiceImpl_RevokeService 2398 }; 2399 2400 static void test_IUnknown_ProfferService(void) 2401 { 2402 IServiceProvider *provider; 2403 IProfferService *proff; 2404 static const GUID dummy_serviceid = { 0xdeadbeef }; 2405 call_trace_t trace_expected; 2406 HRESULT hr; 2407 DWORD cookie; 2408 2409 provider = IServiceProviderImpl_Construct(); 2410 proff = IProfferServiceImpl_Construct(); 2411 2412 /* null source pointer */ 2413 hr = pIUnknown_ProfferService(NULL, &dummy_serviceid, 0, 0); 2414 ok(hr == E_FAIL || 2415 hr == E_NOTIMPL, /* win 8 */ 2416 "got 0x%08x\n", hr); 2417 2418 /* expected trace: 2419 IUnknown_ProfferService( ptr1, serviceid, arg1, arg2); 2420 -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &provider ); 2421 -> IServiceProvider_QueryService( provider, &IID_IProfferService, &IID_IProfferService, &proffer ); 2422 2423 if (service pointer not null): 2424 -> IProfferService_ProfferService( proffer, serviceid, arg1, arg2 ); 2425 else 2426 -> IProfferService_RevokeService( proffer, *arg2 ); 2427 */ 2428 init_call_trace(&trace_expected); 2429 2430 add_call(&trace_expected, 1, proff, &IID_IServiceProvider, 0, 0, 0); 2431 add_call(&trace_expected, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0); 2432 add_call(&trace_expected, 3, &dummy_serviceid, provider, &cookie, 0, 0); 2433 2434 init_call_trace(&trace_got); 2435 cookie = 0; 2436 hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, provider, &cookie); 2437 ok(hr == S_OK, "got 0x%08x\n", hr); 2438 ok(cookie == 0xdeadbeef, "got %x\n", cookie); 2439 2440 ok_trace(&trace_expected, &trace_got); 2441 free_call_trace(&trace_got); 2442 free_call_trace(&trace_expected); 2443 2444 /* same with ::Revoke path */ 2445 init_call_trace(&trace_expected); 2446 2447 add_call(&trace_expected, 1, proff, &IID_IServiceProvider, 0, 0, 0); 2448 add_call(&trace_expected, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0); 2449 add_call(&trace_expected, 4, (void*)(DWORD_PTR)cookie, 0, 0, 0, 0); 2450 2451 init_call_trace(&trace_got); 2452 ok(cookie != 0, "got %x\n", cookie); 2453 hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, 0, &cookie); 2454 ok(hr == S_OK, "got 0x%08x\n", hr); 2455 ok(cookie == 0, "got %x\n", cookie); 2456 ok_trace(&trace_expected, &trace_got); 2457 free_call_trace(&trace_got); 2458 free_call_trace(&trace_expected); 2459 2460 IServiceProvider_Release(provider); 2461 IProfferService_Release(proff); 2462 } 2463 2464 static void test_SHCreateWorkerWindowA(void) 2465 { 2466 WNDCLASSA cliA; 2467 char classA[20]; 2468 HWND hwnd; 2469 LONG_PTR ret; 2470 BOOL res; 2471 2472 hwnd = pSHCreateWorkerWindowA(0, NULL, 0, 0, 0, 0); 2473 ok(hwnd != 0, "expected window\n"); 2474 2475 GetClassNameA(hwnd, classA, 20); 2476 ok(lstrcmpA(classA, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA); 2477 2478 ret = GetWindowLongPtrA(hwnd, 0); 2479 ok(ret == 0, "got %ld\n", ret); 2480 2481 /* class info */ 2482 memset(&cliA, 0, sizeof(cliA)); 2483 res = GetClassInfoA(GetModuleHandleA("shlwapi.dll"), "WorkerA", &cliA); 2484 ok(res, "failed to get class info\n"); 2485 ok(cliA.style == 0, "got 0x%08x\n", cliA.style); 2486 ok(cliA.cbClsExtra == 0, "got %d\n", cliA.cbClsExtra); 2487 ok(cliA.cbWndExtra == sizeof(LONG_PTR), "got %d\n", cliA.cbWndExtra); 2488 ok(cliA.lpszMenuName == 0, "got %s\n", cliA.lpszMenuName); 2489 2490 DestroyWindow(hwnd); 2491 2492 /* set extra bytes */ 2493 hwnd = pSHCreateWorkerWindowA(0, NULL, 0, 0, 0, 0xdeadbeef); 2494 ok(hwnd != 0, "expected window\n"); 2495 2496 GetClassNameA(hwnd, classA, 20); 2497 ok(lstrcmpA(classA, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA); 2498 2499 ret = GetWindowLongPtrA(hwnd, 0); 2500 ok(ret == 0xdeadbeef, "got %ld\n", ret); 2501 2502 /* test exstyle */ 2503 ret = GetWindowLongA(hwnd, GWL_EXSTYLE); 2504 ok(ret == WS_EX_WINDOWEDGE || 2505 ret == (WS_EX_WINDOWEDGE|WS_EX_LAYOUTRTL) /* systems with RTL locale */, "0x%08lx\n", ret); 2506 2507 DestroyWindow(hwnd); 2508 2509 hwnd = pSHCreateWorkerWindowA(0, NULL, WS_EX_TOOLWINDOW, 0, 0, 0); 2510 ret = GetWindowLongA(hwnd, GWL_EXSTYLE); 2511 ok(ret == (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW) || 2512 ret == (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW|WS_EX_LAYOUTRTL) /* systems with RTL locale */, "0x%08lx\n", ret); 2513 DestroyWindow(hwnd); 2514 } 2515 2516 static HRESULT WINAPI SF_QueryInterface(IShellFolder *iface, 2517 REFIID riid, void **ppv) 2518 { 2519 /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */ 2520 ok(!IsEqualGUID(&IID_IShellFolder, riid), 2521 "Unexpected QI for IShellFolder\n"); 2522 return E_NOINTERFACE; 2523 } 2524 2525 static ULONG WINAPI SF_AddRef(IShellFolder *iface) 2526 { 2527 return 2; 2528 } 2529 2530 static ULONG WINAPI SF_Release(IShellFolder *iface) 2531 { 2532 return 1; 2533 } 2534 2535 static HRESULT WINAPI SF_ParseDisplayName(IShellFolder *iface, 2536 HWND owner, LPBC reserved, LPOLESTR displayName, ULONG *eaten, 2537 LPITEMIDLIST *idl, ULONG *attr) 2538 { 2539 ok(0, "Didn't expect ParseDisplayName\n"); 2540 return E_NOTIMPL; 2541 } 2542 2543 static HRESULT WINAPI SF_EnumObjects(IShellFolder *iface, 2544 HWND owner, SHCONTF flags, IEnumIDList **enm) 2545 { 2546 *enm = (IEnumIDList*)0xcafebabe; 2547 return S_OK; 2548 } 2549 2550 static HRESULT WINAPI SF_BindToObject(IShellFolder *iface, 2551 LPCITEMIDLIST idl, LPBC reserved, REFIID riid, void **obj) 2552 { 2553 ok(0, "Didn't expect BindToObject\n"); 2554 return E_NOTIMPL; 2555 } 2556 2557 static HRESULT WINAPI SF_BindToStorage(IShellFolder *iface, 2558 LPCITEMIDLIST idl, LPBC reserved, REFIID riid, void **obj) 2559 { 2560 ok(0, "Didn't expect BindToStorage\n"); 2561 return E_NOTIMPL; 2562 } 2563 2564 static HRESULT WINAPI SF_CompareIDs(IShellFolder *iface, 2565 LPARAM lparam, LPCITEMIDLIST idl1, LPCITEMIDLIST idl2) 2566 { 2567 ok(0, "Didn't expect CompareIDs\n"); 2568 return E_NOTIMPL; 2569 } 2570 2571 static HRESULT WINAPI SF_CreateViewObject(IShellFolder *iface, 2572 HWND owner, REFIID riid, void **out) 2573 { 2574 ok(0, "Didn't expect CreateViewObject\n"); 2575 return E_NOTIMPL; 2576 } 2577 2578 static HRESULT WINAPI SF_GetAttributesOf(IShellFolder *iface, 2579 #ifdef __REACTOS__ 2580 UINT cidl, PCUITEMID_CHILD_ARRAY idl, SFGAOF *inOut) 2581 #else 2582 UINT cidl, LPCITEMIDLIST *idl, SFGAOF *inOut) 2583 #endif 2584 { 2585 ok(0, "Didn't expect GetAttributesOf\n"); 2586 return E_NOTIMPL; 2587 } 2588 2589 static HRESULT WINAPI SF_GetUIObjectOf(IShellFolder *iface, 2590 #ifdef __REACTOS__ 2591 HWND owner, UINT cidl, PCUITEMID_CHILD_ARRAY idls, REFIID riid, UINT *inOut, 2592 #else 2593 HWND owner, UINT cidl, LPCITEMIDLIST *idls, REFIID riid, UINT *inOut, 2594 #endif 2595 void **out) 2596 { 2597 ok(0, "Didn't expect GetUIObjectOf\n"); 2598 return E_NOTIMPL; 2599 } 2600 2601 static HRESULT WINAPI SF_GetDisplayNameOf(IShellFolder *iface, 2602 LPCITEMIDLIST idl, SHGDNF flags, STRRET *name) 2603 { 2604 ok(0, "Didn't expect GetDisplayNameOf\n"); 2605 return E_NOTIMPL; 2606 } 2607 2608 static HRESULT WINAPI SF_SetNameOf(IShellFolder *iface, 2609 HWND hwnd, LPCITEMIDLIST idl, LPCOLESTR name, SHGDNF flags, 2610 LPITEMIDLIST *idlOut) 2611 { 2612 ok(0, "Didn't expect SetNameOf\n"); 2613 return E_NOTIMPL; 2614 } 2615 2616 static IShellFolderVtbl ShellFolderVtbl = { 2617 SF_QueryInterface, 2618 SF_AddRef, 2619 SF_Release, 2620 SF_ParseDisplayName, 2621 SF_EnumObjects, 2622 SF_BindToObject, 2623 SF_BindToStorage, 2624 SF_CompareIDs, 2625 SF_CreateViewObject, 2626 SF_GetAttributesOf, 2627 SF_GetUIObjectOf, 2628 SF_GetDisplayNameOf, 2629 SF_SetNameOf 2630 }; 2631 2632 static IShellFolder ShellFolder = { &ShellFolderVtbl }; 2633 2634 static void test_SHIShellFolder_EnumObjects(void) 2635 { 2636 IEnumIDList *enm; 2637 HRESULT hres; 2638 IShellFolder *folder; 2639 2640 if(!pSHIShellFolder_EnumObjects){ /* win7 and later */ 2641 win_skip("SHIShellFolder_EnumObjects not available\n"); 2642 return; 2643 } 2644 2645 if(0){ 2646 /* NULL object crashes on Windows */ 2647 pSHIShellFolder_EnumObjects(NULL, NULL, 0, NULL); 2648 } 2649 2650 /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */ 2651 enm = (IEnumIDList*)0xdeadbeef; 2652 hres = pSHIShellFolder_EnumObjects(&ShellFolder, NULL, 0, &enm); 2653 ok(hres == S_OK, "SHIShellFolder_EnumObjects failed: 0x%08x\n", hres); 2654 ok(enm == (IEnumIDList*)0xcafebabe, "Didn't get expected enumerator location, instead: %p\n", enm); 2655 2656 /* SHIShellFolder_EnumObjects isn't strict about the IShellFolder object */ 2657 hres = SHGetDesktopFolder(&folder); 2658 ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres); 2659 2660 enm = NULL; 2661 hres = pSHIShellFolder_EnumObjects(folder, NULL, 0, &enm); 2662 ok(hres == S_OK, "SHIShellFolder_EnumObjects failed: 0x%08x\n", hres); 2663 ok(enm != NULL, "Didn't get an enumerator\n"); 2664 if(enm) 2665 IEnumIDList_Release(enm); 2666 2667 IShellFolder_Release(folder); 2668 } 2669 2670 static BOOL write_inifile(LPCWSTR filename) 2671 { 2672 DWORD written; 2673 HANDLE file; 2674 2675 static const char data[] = 2676 "[TestApp]\r\n" 2677 "AKey=1\r\n" 2678 "AnotherKey=asdf\r\n"; 2679 2680 file = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); 2681 if(file == INVALID_HANDLE_VALUE) { 2682 win_skip("failed to create ini file at %s\n", wine_dbgstr_w(filename)); 2683 return FALSE; 2684 } 2685 2686 WriteFile(file, data, sizeof(data), &written, NULL); 2687 2688 CloseHandle(file); 2689 2690 return TRUE; 2691 } 2692 2693 #define verify_inifile(f, e) r_verify_inifile(__LINE__, f, e) 2694 static void r_verify_inifile(unsigned l, LPCWSTR filename, LPCSTR exp) 2695 { 2696 HANDLE file; 2697 CHAR buf[1024]; 2698 DWORD read; 2699 2700 file = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); 2701 2702 if(file == INVALID_HANDLE_VALUE) 2703 return; 2704 2705 ReadFile(file, buf, sizeof(buf) * sizeof(CHAR), &read, NULL); 2706 buf[read] = '\0'; 2707 2708 CloseHandle(file); 2709 2710 ok_(__FILE__,l)(!strcmp(buf, exp), "Expected:\n%s\nGot:\n%s\n", exp, 2711 buf); 2712 } 2713 2714 static void test_SHGetIniString(void) 2715 { 2716 DWORD ret; 2717 WCHAR out[64] = {0}; 2718 2719 static const WCHAR TestAppW[] = {'T','e','s','t','A','p','p',0}; 2720 static const WCHAR AKeyW[] = {'A','K','e','y',0}; 2721 static const WCHAR AnotherKeyW[] = {'A','n','o','t','h','e','r','K','e','y',0}; 2722 static const WCHAR JunkKeyW[] = {'J','u','n','k','K','e','y',0}; 2723 static const WCHAR testpathW[] = {'C',':','\\','t','e','s','t','.','i','n','i',0}; 2724 WCHAR pathW[MAX_PATH]; 2725 2726 lstrcpyW(pathW, testpathW); 2727 2728 if (!write_inifile(pathW)) 2729 return; 2730 2731 if(0){ 2732 /* these crash on Windows */ 2733 pSHGetIniStringW(NULL, NULL, NULL, 0, NULL); 2734 pSHGetIniStringW(NULL, AKeyW, out, sizeof(out), pathW); 2735 pSHGetIniStringW(TestAppW, AKeyW, NULL, sizeof(out), pathW); 2736 } 2737 2738 ret = pSHGetIniStringW(TestAppW, AKeyW, out, 0, pathW); 2739 ok(ret == 0, "SHGetIniStringW should have given 0, instead: %d\n", ret); 2740 2741 /* valid arguments */ 2742 out[0] = 0; 2743 SetLastError(0xdeadbeef); 2744 ret = pSHGetIniStringW(TestAppW, NULL, out, sizeof(out), pathW); 2745 ok(ret == 4, "SHGetIniStringW should have given 4, instead: %d\n", ret); 2746 ok(!lstrcmpW(out, AKeyW), "Expected %s, got: %s, %d\n", 2747 wine_dbgstr_w(AKeyW), wine_dbgstr_w(out), GetLastError()); 2748 2749 ret = pSHGetIniStringW(TestAppW, AKeyW, out, sizeof(out), pathW); 2750 ok(ret == 1, "SHGetIniStringW should have given 1, instead: %d\n", ret); 2751 ok(!strcmp_wa(out, "1"), "Expected L\"1\", got: %s\n", wine_dbgstr_w(out)); 2752 2753 ret = pSHGetIniStringW(TestAppW, AnotherKeyW, out, sizeof(out), pathW); 2754 ok(ret == 4, "SHGetIniStringW should have given 4, instead: %d\n", ret); 2755 ok(!strcmp_wa(out, "asdf"), "Expected L\"asdf\", got: %s\n", wine_dbgstr_w(out)); 2756 2757 out[0] = 1; 2758 ret = pSHGetIniStringW(TestAppW, JunkKeyW, out, sizeof(out), pathW); 2759 ok(ret == 0, "SHGetIniStringW should have given 0, instead: %d\n", ret); 2760 ok(*out == 0, "Expected L\"\", got: %s\n", wine_dbgstr_w(out)); 2761 2762 DeleteFileW(pathW); 2763 } 2764 2765 static void test_SHSetIniString(void) 2766 { 2767 BOOL ret; 2768 2769 static const WCHAR TestAppW[] = {'T','e','s','t','A','p','p',0}; 2770 static const WCHAR AnotherAppW[] = {'A','n','o','t','h','e','r','A','p','p',0}; 2771 static const WCHAR TestIniW[] = {'C',':','\\','t','e','s','t','.','i','n','i',0}; 2772 static const WCHAR AKeyW[] = {'A','K','e','y',0}; 2773 static const WCHAR NewKeyW[] = {'N','e','w','K','e','y',0}; 2774 static const WCHAR AValueW[] = {'A','V','a','l','u','e',0}; 2775 2776 if (!write_inifile(TestIniW)) 2777 return; 2778 2779 ret = pSHSetIniStringW(TestAppW, AKeyW, AValueW, TestIniW); 2780 ok(ret == TRUE, "SHSetIniStringW should not have failed\n"); 2781 todo_wine /* wine sticks an extra \r\n at the end of the file */ 2782 verify_inifile(TestIniW, "[TestApp]\r\nAKey=AValue\r\nAnotherKey=asdf\r\n"); 2783 2784 ret = pSHSetIniStringW(TestAppW, AKeyW, NULL, TestIniW); 2785 ok(ret == TRUE, "SHSetIniStringW should not have failed\n"); 2786 verify_inifile(TestIniW, "[TestApp]\r\nAnotherKey=asdf\r\n"); 2787 2788 ret = pSHSetIniStringW(AnotherAppW, NewKeyW, AValueW, TestIniW); 2789 ok(ret == TRUE, "SHSetIniStringW should not have failed\n"); 2790 verify_inifile(TestIniW, "[TestApp]\r\nAnotherKey=asdf\r\n[AnotherApp]\r\nNewKey=AValue\r\n"); 2791 2792 ret = pSHSetIniStringW(TestAppW, NULL, AValueW, TestIniW); 2793 ok(ret == TRUE, "SHSetIniStringW should not have failed\n"); 2794 verify_inifile(TestIniW, "[AnotherApp]\r\nNewKey=AValue\r\n"); 2795 2796 DeleteFileW(TestIniW); 2797 } 2798 2799 enum _shellkey_flags { 2800 SHKEY_Root_HKCU = 0x1, 2801 SHKEY_Root_HKLM = 0x2, 2802 SHKEY_Key_Explorer = 0x00, 2803 SHKEY_Key_Shell = 0x10, 2804 SHKEY_Key_ShellNoRoam = 0x20, 2805 SHKEY_Key_Classes = 0x30, 2806 SHKEY_Subkey_Default = 0x0000, 2807 SHKEY_Subkey_ResourceName = 0x1000, 2808 SHKEY_Subkey_Handlers = 0x2000, 2809 SHKEY_Subkey_Associations = 0x3000, 2810 SHKEY_Subkey_Volatile = 0x4000, 2811 SHKEY_Subkey_MUICache = 0x5000, 2812 SHKEY_Subkey_FileExts = 0x6000 2813 }; 2814 2815 static void test_SHGetShellKey(void) 2816 { 2817 static const WCHAR ShellFoldersW[] = { 'S','h','e','l','l',' ','F','o','l','d','e','r','s',0 }; 2818 static const WCHAR WineTestW[] = { 'W','i','n','e','T','e','s','t',0 }; 2819 2820 DWORD *alloc_data, data, size; 2821 HKEY hkey; 2822 HRESULT hres; 2823 2824 /* Vista+ limits SHKEY enumeration values */ 2825 SetLastError(0xdeadbeef); 2826 hkey = pSHGetShellKey(SHKEY_Key_Explorer, ShellFoldersW, FALSE); 2827 if (hkey) 2828 { 2829 /* Tests not working on Vista+ */ 2830 RegCloseKey(hkey); 2831 2832 hkey = pSHGetShellKey(SHKEY_Root_HKLM|SHKEY_Key_Classes, NULL, FALSE); 2833 ok(hkey != NULL, "hkey = NULL\n"); 2834 RegCloseKey(hkey); 2835 } 2836 2837 hkey = pSHGetShellKey(SHKEY_Root_HKCU|SHKEY_Key_Explorer, ShellFoldersW, FALSE); 2838 ok(hkey != NULL, "hkey = NULL\n"); 2839 RegCloseKey(hkey); 2840 2841 hkey = pSHGetShellKey(SHKEY_Root_HKLM|SHKEY_Key_Explorer, ShellFoldersW, FALSE); 2842 ok(hkey != NULL, "hkey = NULL\n"); 2843 RegCloseKey(hkey); 2844 2845 hkey = pSHGetShellKey(SHKEY_Root_HKLM, WineTestW, FALSE); 2846 ok(hkey == NULL, "hkey != NULL\n"); 2847 2848 hkey = pSHGetShellKey(SHKEY_Root_HKLM, NULL, FALSE); 2849 ok(hkey != NULL, "Can't open key\n"); 2850 ok(SUCCEEDED(RegDeleteKeyW(hkey, WineTestW)), "Can't delete key\n"); 2851 RegCloseKey(hkey); 2852 2853 hkey = pSHGetShellKey(SHKEY_Root_HKLM, WineTestW, TRUE); 2854 if (!hkey && GetLastError() == ERROR_ACCESS_DENIED) 2855 { 2856 skip("Not authorized to create keys\n"); 2857 return; 2858 } 2859 ok(hkey != NULL, "Can't create key\n"); 2860 RegCloseKey(hkey); 2861 2862 size = sizeof(data); 2863 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size); 2864 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres); 2865 2866 data = 1234; 2867 hres = pSKSetValueW(SHKEY_Root_HKLM, WineTestW, NULL, REG_DWORD, &data, sizeof(DWORD)); 2868 ok(hres == S_OK, "hres = %x\n", hres); 2869 2870 size = 1; 2871 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, NULL, &size); 2872 ok(hres == S_OK, "hres = %x\n", hres); 2873 ok(size == sizeof(DWORD), "size = %d\n", size); 2874 2875 data = 0xdeadbeef; 2876 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size); 2877 ok(hres == S_OK, "hres = %x\n", hres); 2878 ok(size == sizeof(DWORD), "size = %d\n", size); 2879 ok(data == 1234, "data = %d\n", data); 2880 2881 hres = pSKAllocValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, (void**)&alloc_data, &size); 2882 ok(hres == S_OK, "hres= %x\n", hres); 2883 ok(size == sizeof(DWORD), "size = %d\n", size); 2884 if (SUCCEEDED(hres)) 2885 { 2886 ok(*alloc_data == 1234, "*alloc_data = %d\n", *alloc_data); 2887 LocalFree(alloc_data); 2888 } 2889 2890 hres = pSKDeleteValueW(SHKEY_Root_HKLM, WineTestW, NULL); 2891 ok(hres == S_OK, "hres = %x\n", hres); 2892 2893 hres = pSKDeleteValueW(SHKEY_Root_HKLM, WineTestW, NULL); 2894 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres); 2895 2896 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size); 2897 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres); 2898 2899 hkey = pSHGetShellKey(SHKEY_Root_HKLM, NULL, FALSE); 2900 ok(hkey != NULL, "Can't create key\n"); 2901 ok(SUCCEEDED(RegDeleteKeyW(hkey, WineTestW)), "Can't delete key\n"); 2902 RegCloseKey(hkey); 2903 } 2904 2905 static void init_pointers(void) 2906 { 2907 #define MAKEFUNC(f, ord) (p##f = (void*)GetProcAddress(hShlwapi, (LPSTR)(ord))) 2908 MAKEFUNC(SHAllocShared, 7); 2909 MAKEFUNC(SHLockShared, 8); 2910 MAKEFUNC(SHUnlockShared, 9); 2911 MAKEFUNC(SHFreeShared, 10); 2912 MAKEFUNC(SHMapHandle, 11); 2913 MAKEFUNC(GetAcceptLanguagesA, 14); 2914 MAKEFUNC(SHSetWindowBits, 165); 2915 MAKEFUNC(SHSetParentHwnd, 167); 2916 MAKEFUNC(ConnectToConnectionPoint, 168); 2917 MAKEFUNC(IUnknown_GetClassID, 175); 2918 MAKEFUNC(SHSearchMapInt, 198); 2919 MAKEFUNC(SHCreateWorkerWindowA, 257); 2920 MAKEFUNC(GUIDFromStringA, 269); 2921 MAKEFUNC(SHPackDispParams, 282); 2922 MAKEFUNC(IConnectionPoint_InvokeWithCancel, 283); 2923 MAKEFUNC(IConnectionPoint_SimpleInvoke, 284); 2924 MAKEFUNC(SHGetIniStringW, 294); 2925 MAKEFUNC(SHSetIniStringW, 295); 2926 MAKEFUNC(SHFormatDateTimeA, 353); 2927 MAKEFUNC(SHFormatDateTimeW, 354); 2928 MAKEFUNC(SHIShellFolder_EnumObjects, 404); 2929 MAKEFUNC(GetShellSecurityDescriptor, 475); 2930 MAKEFUNC(SHGetObjectCompatFlags, 476); 2931 MAKEFUNC(IUnknown_QueryServiceExec, 484); 2932 MAKEFUNC(SHGetShellKey, 491); 2933 MAKEFUNC(SHPropertyBag_ReadLONG, 496); 2934 MAKEFUNC(IUnknown_ProfferService, 514); 2935 MAKEFUNC(SKGetValueW, 516); 2936 MAKEFUNC(SKSetValueW, 517); 2937 MAKEFUNC(SKDeleteValueW, 518); 2938 MAKEFUNC(SKAllocValueW, 519); 2939 #undef MAKEFUNC 2940 2941 pDllGetVersion = (void*)GetProcAddress(hShlwapi, "DllGetVersion"); 2942 } 2943 2944 static void test_SHSetParentHwnd(void) 2945 { 2946 HWND hwnd, hwnd2, ret; 2947 DWORD style; 2948 2949 hwnd = CreateWindowA("Button", "", WS_VISIBLE, 0, 0, 10, 10, NULL, NULL, NULL, NULL); 2950 ok(hwnd != NULL, "got %p\n", hwnd); 2951 2952 hwnd2 = CreateWindowA("Button", "", WS_VISIBLE | WS_CHILD, 0, 0, 10, 10, hwnd, NULL, NULL, NULL); 2953 ok(hwnd2 != NULL, "got %p\n", hwnd2); 2954 2955 /* null params */ 2956 ret = pSHSetParentHwnd(NULL, NULL); 2957 ok(ret == NULL, "got %p\n", ret); 2958 2959 /* set to no parent while already no parent present */ 2960 ret = GetParent(hwnd); 2961 ok(ret == NULL, "got %p\n", ret); 2962 style = GetWindowLongA(hwnd, GWL_STYLE); 2963 ok((style & (WS_POPUP|WS_CHILD)) == 0, "got style 0x%08x\n", style); 2964 ret = pSHSetParentHwnd(hwnd, NULL); 2965 ok(ret == NULL, "got %p\n", ret); 2966 style = GetWindowLongA(hwnd, GWL_STYLE); 2967 ok((style & (WS_POPUP|WS_CHILD)) == 0, "got style 0x%08x\n", style); 2968 2969 /* reset to null parent from not null */ 2970 ret = GetParent(hwnd2); 2971 ok(ret == hwnd, "got %p\n", ret); 2972 style = GetWindowLongA(hwnd2, GWL_STYLE); 2973 ok((style & (WS_POPUP|WS_CHILD)) == WS_CHILD, "got style 0x%08x\n", style); 2974 ret = pSHSetParentHwnd(hwnd2, NULL); 2975 ok(ret == NULL, "got %p\n", ret); 2976 style = GetWindowLongA(hwnd2, GWL_STYLE); 2977 ok((style & (WS_POPUP|WS_CHILD)) == WS_POPUP, "got style 0x%08x\n", style); 2978 ret = GetParent(hwnd2); 2979 ok(ret == NULL, "got %p\n", ret); 2980 2981 /* set parent back */ 2982 style = GetWindowLongA(hwnd2, GWL_STYLE); 2983 SetWindowLongA(hwnd2, GWL_STYLE, style & ~(WS_CHILD|WS_POPUP)); 2984 style = GetWindowLongA(hwnd2, GWL_STYLE); 2985 ok((style & (WS_CHILD|WS_POPUP)) == 0, "got 0x%08x\n", style); 2986 2987 ret = pSHSetParentHwnd(hwnd2, hwnd); 2988 todo_wine ok(ret == NULL, "got %p\n", ret); 2989 2990 style = GetWindowLongA(hwnd2, GWL_STYLE); 2991 ok((style & (WS_POPUP|WS_CHILD)) == WS_CHILD, "got style 0x%08x\n", style); 2992 ret = GetParent(hwnd2); 2993 ok(ret == hwnd, "got %p\n", ret); 2994 2995 /* try to set same parent again */ 2996 /* with WS_POPUP */ 2997 style = GetWindowLongA(hwnd2, GWL_STYLE); 2998 SetWindowLongA(hwnd2, GWL_STYLE, style | WS_POPUP); 2999 ret = pSHSetParentHwnd(hwnd2, hwnd); 3000 todo_wine ok(ret == NULL, "got %p\n", ret); 3001 style = GetWindowLongA(hwnd2, GWL_STYLE); 3002 ok((style & (WS_CHILD|WS_POPUP)) == WS_CHILD, "got 0x%08x\n", style); 3003 ret = GetParent(hwnd2); 3004 ok(ret == hwnd, "got %p\n", ret); 3005 3006 /* without WS_POPUP */ 3007 style = GetWindowLongA(hwnd2, GWL_STYLE); 3008 SetWindowLongA(hwnd2, GWL_STYLE, style | ~WS_POPUP); 3009 ret = pSHSetParentHwnd(hwnd2, hwnd); 3010 todo_wine ok(ret == hwnd, "got %p\n", ret); 3011 style = GetWindowLongA(hwnd2, GWL_STYLE); 3012 ok((style & (WS_CHILD|WS_POPUP)) == WS_CHILD, "got 0x%08x\n", style); 3013 ret = GetParent(hwnd2); 3014 ok(ret == hwnd, "got %p\n", ret); 3015 3016 DestroyWindow(hwnd); 3017 DestroyWindow(hwnd2); 3018 } 3019 3020 static HRESULT WINAPI testpersist_QI(IPersist *iface, REFIID riid, void **obj) 3021 { 3022 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPersist)) { 3023 *obj = iface; 3024 IPersist_AddRef(iface); 3025 return S_OK; 3026 } 3027 3028 *obj = NULL; 3029 return E_NOINTERFACE; 3030 } 3031 3032 static HRESULT WINAPI testpersist_QI2(IPersist *iface, REFIID riid, void **obj) 3033 { 3034 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPersistFolder)) { 3035 *obj = iface; 3036 IPersist_AddRef(iface); 3037 return S_OK; 3038 } 3039 3040 *obj = NULL; 3041 return E_NOINTERFACE; 3042 } 3043 3044 static ULONG WINAPI testpersist_AddRef(IPersist *iface) 3045 { 3046 return 2; 3047 } 3048 3049 static ULONG WINAPI testpersist_Release(IPersist *iface) 3050 { 3051 return 1; 3052 } 3053 3054 static HRESULT WINAPI testpersist_GetClassID(IPersist *iface, CLSID *clsid) 3055 { 3056 memset(clsid, 0xab, sizeof(*clsid)); 3057 return 0x8fff2222; 3058 } 3059 3060 static IPersistVtbl testpersistvtbl = { 3061 testpersist_QI, 3062 testpersist_AddRef, 3063 testpersist_Release, 3064 testpersist_GetClassID 3065 }; 3066 3067 static IPersistVtbl testpersist2vtbl = { 3068 testpersist_QI2, 3069 testpersist_AddRef, 3070 testpersist_Release, 3071 testpersist_GetClassID 3072 }; 3073 3074 static IPersist testpersist = { &testpersistvtbl }; 3075 static IPersist testpersist2 = { &testpersist2vtbl }; 3076 3077 static void test_IUnknown_GetClassID(void) 3078 { 3079 CLSID clsid, clsid2, clsid3; 3080 HRESULT hr; 3081 3082 if (0) /* crashes on native systems */ 3083 hr = pIUnknown_GetClassID(NULL, NULL); 3084 3085 memset(&clsid, 0xcc, sizeof(clsid)); 3086 memset(&clsid3, 0xcc, sizeof(clsid3)); 3087 hr = pIUnknown_GetClassID(NULL, &clsid); 3088 ok(hr == E_FAIL, "got 0x%08x\n", hr); 3089 ok(IsEqualCLSID(&clsid, &CLSID_NULL) || broken(IsEqualCLSID(&clsid, &clsid3)) /* win2k, winxp, win2k3 */, 3090 "got wrong clsid %s\n", wine_dbgstr_guid(&clsid)); 3091 3092 memset(&clsid, 0xcc, sizeof(clsid)); 3093 memset(&clsid2, 0xab, sizeof(clsid2)); 3094 hr = pIUnknown_GetClassID((IUnknown*)&testpersist, &clsid); 3095 ok(hr == 0x8fff2222, "got 0x%08x\n", hr); 3096 ok(IsEqualCLSID(&clsid, &clsid2) || broken(IsEqualCLSID(&clsid, &clsid3)) /* win2k3 */, 3097 "got wrong clsid %s\n", wine_dbgstr_guid(&clsid)); 3098 3099 /* IPersistFolder is also supported */ 3100 memset(&clsid, 0xcc, sizeof(clsid)); 3101 memset(&clsid2, 0xab, sizeof(clsid2)); 3102 memset(&clsid3, 0xcc, sizeof(clsid3)); 3103 hr = pIUnknown_GetClassID((IUnknown*)&testpersist2, &clsid); 3104 ok(hr == 0x8fff2222, "got 0x%08x\n", hr); 3105 ok(IsEqualCLSID(&clsid, &clsid2) || broken(IsEqualCLSID(&clsid, &clsid3)) /* win2k3 */, 3106 "got wrong clsid %s\n", wine_dbgstr_guid(&clsid)); 3107 } 3108 3109 static void test_DllGetVersion(void) 3110 { 3111 HRESULT hr; 3112 3113 hr = pDllGetVersion(NULL); 3114 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); 3115 } 3116 3117 START_TEST(ordinal) 3118 { 3119 char **argv; 3120 int argc; 3121 3122 hShlwapi = GetModuleHandleA("shlwapi.dll"); 3123 3124 init_pointers(); 3125 3126 argc = winetest_get_mainargs(&argv); 3127 if (argc >= 4) 3128 { 3129 DWORD procid; 3130 HANDLE hmem; 3131 sscanf(argv[2], "%d", &procid); 3132 sscanf(argv[3], "%p", &hmem); 3133 test_alloc_shared_remote(procid, hmem); 3134 return; 3135 } 3136 3137 test_GetAcceptLanguagesA(); 3138 test_SHSearchMapInt(); 3139 test_alloc_shared(argc, argv); 3140 test_fdsa(); 3141 test_GetShellSecurityDescriptor(); 3142 test_SHPackDispParams(); 3143 test_IConnectionPoint(); 3144 test_SHPropertyBag_ReadLONG(); 3145 test_SHSetWindowBits(); 3146 test_SHFormatDateTimeA(); 3147 test_SHFormatDateTimeW(); 3148 test_SHGetObjectCompatFlags(); 3149 test_IUnknown_QueryServiceExec(); 3150 test_IUnknown_ProfferService(); 3151 test_SHCreateWorkerWindowA(); 3152 test_SHIShellFolder_EnumObjects(); 3153 test_SHGetIniString(); 3154 test_SHSetIniString(); 3155 test_SHGetShellKey(); 3156 test_SHSetParentHwnd(); 3157 test_IUnknown_GetClassID(); 3158 test_DllGetVersion(); 3159 } 3160