1 /* Unit test suite for SHLWAPI ordinal functions
3 * Copyright 2004 Jon Griffiths
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.
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.
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
24 #include "wine/test.h"
37 /* Function ptrs for ordinal calls */
38 static HMODULE hShlwapi;
39 static BOOL is_win2k_and_lower;
42 static int (WINAPI *pSHSearchMapInt)(const int*,const int*,int,int);
43 static HRESULT (WINAPI *pGetAcceptLanguagesA)(LPSTR,LPDWORD);
45 static HANDLE (WINAPI *pSHAllocShared)(LPCVOID,DWORD,DWORD);
46 static LPVOID (WINAPI *pSHLockShared)(HANDLE,DWORD);
47 static BOOL (WINAPI *pSHUnlockShared)(LPVOID);
48 static BOOL (WINAPI *pSHFreeShared)(HANDLE,DWORD);
49 static HRESULT(WINAPIV *pSHPackDispParams)(DISPPARAMS*,VARIANTARG*,UINT,...);
50 static HRESULT(WINAPI *pIConnectionPoint_SimpleInvoke)(IConnectionPoint*,DISPID,DISPPARAMS*);
51 static HRESULT(WINAPI *pIConnectionPoint_InvokeWithCancel)(IConnectionPoint*,DISPID,DISPPARAMS*,DWORD,DWORD);
52 static HRESULT(WINAPI *pConnectToConnectionPoint)(IUnknown*,REFIID,BOOL,IUnknown*, LPDWORD,IConnectionPoint **);
53 static HRESULT(WINAPI *pSHPropertyBag_ReadLONG)(IPropertyBag *,LPCWSTR,LPLONG);
54 static LONG (WINAPI *pSHSetWindowBits)(HWND, INT, UINT, UINT);
55 static INT (WINAPI *pSHFormatDateTimeA)(const FILETIME UNALIGNED*, DWORD*, LPSTR, UINT);
56 static INT (WINAPI *pSHFormatDateTimeW)(const FILETIME UNALIGNED*, DWORD*, LPWSTR, UINT);
57 static DWORD (WINAPI *pSHGetObjectCompatFlags)(IUnknown*, const CLSID*);
58 static BOOL (WINAPI *pGUIDFromStringA)(LPSTR, CLSID *);
59 static HRESULT (WINAPI *pIUnknown_QueryServiceExec)(IUnknown*, REFIID, const GUID*, DWORD, DWORD, VARIANT*, VARIANT*);
60 static HRESULT (WINAPI *pIUnknown_ProfferService)(IUnknown*, REFGUID, IServiceProvider*, DWORD*);
61 static HWND (WINAPI *pSHCreateWorkerWindowA)(LONG, HWND, DWORD, DWORD, HMENU, LONG_PTR);
62 static HRESULT (WINAPI *pSHIShellFolder_EnumObjects)(LPSHELLFOLDER, HWND, SHCONTF, IEnumIDList**);
63 static DWORD (WINAPI *pSHGetIniStringW)(LPCWSTR, LPCWSTR, LPWSTR, DWORD, LPCWSTR);
64 static BOOL (WINAPI *pSHSetIniStringW)(LPCWSTR, LPCWSTR, LPCWSTR, LPCWSTR);
65 static HKEY (WINAPI *pSHGetShellKey)(DWORD, LPCWSTR, BOOL);
66 static HRESULT (WINAPI *pSKGetValueW)(DWORD, LPCWSTR, LPCWSTR, DWORD*, void*, DWORD*);
67 static HRESULT (WINAPI *pSKSetValueW)(DWORD, LPCWSTR, LPCWSTR, DWORD, void*, DWORD);
68 static HRESULT (WINAPI *pSKDeleteValueW)(DWORD, LPCWSTR, LPCWSTR);
69 static HRESULT (WINAPI *pSKAllocValueW)(DWORD, LPCWSTR, LPCWSTR, DWORD*, void**, DWORD*);
71 static HMODULE hmlang;
72 static HRESULT (WINAPI *pLcidToRfc1766A)(LCID, LPSTR, INT);
74 static HMODULE hshell32;
75 static HRESULT (WINAPI *pSHGetDesktopFolder)(IShellFolder**);
77 static const CHAR ie_international[] = {
78 'S','o','f','t','w','a','r','e','\\',
79 'M','i','c','r','o','s','o','f','t','\\',
80 'I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r','\\',
81 'I','n','t','e','r','n','a','t','i','o','n','a','l',0};
82 static const CHAR acceptlanguage[] = {
83 'A','c','c','e','p','t','L','a','n','g','u','a','g','e',0};
85 static int strcmp_wa(LPCWSTR strw, const char *stra)
88 WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL);
89 return lstrcmpA(stra, buf);
103 static void init_call_trace(call_trace_t *ctrace)
107 ctrace->calls = HeapAlloc(GetProcessHeap(), 0, sizeof(call_entry_t) * ctrace->alloc);
110 static void free_call_trace(const call_trace_t *ctrace)
112 HeapFree(GetProcessHeap(), 0, ctrace->calls);
115 static void add_call(call_trace_t *ctrace, int id, const void *arg0,
116 const void *arg1, const void *arg2, const void *arg3, const void *arg4)
127 if (ctrace->count == ctrace->alloc)
130 ctrace->calls = HeapReAlloc(GetProcessHeap(),0, ctrace->calls, ctrace->alloc*sizeof(call_entry_t));
133 ctrace->calls[ctrace->count++] = call;
136 static void ok_trace_(call_trace_t *texpected, call_trace_t *tgot, int line)
138 if (texpected->count == tgot->count)
142 for (i = 0; i < texpected->count; i++)
144 call_entry_t *expected = &texpected->calls[i];
145 call_entry_t *got = &tgot->calls[i];
148 ok_(__FILE__, line)(expected->id == got->id, "got different ids %d: %d, %d\n", i+1, expected->id, got->id);
150 for (j = 0; j < 5; j++)
152 ok_(__FILE__, line)(expected->args[j] == got->args[j], "got different args[%d] for %d: %p, %p\n", j, i+1,
153 expected->args[j], got->args[j]);
158 ok_(__FILE__, line)(0, "traces length mismatch\n");
161 #define ok_trace(a, b) ok_trace_(a, b, __LINE__)
163 /* trace of actually made calls */
164 static call_trace_t trace_got;
166 static void test_GetAcceptLanguagesA(void)
168 static LPCSTR table[] = {"de,en-gb;q=0.7,en;q=0.3",
169 "de,en;q=0.3,en-gb;q=0.7", /* sorting is ignored */
170 "winetest", /* content is ignored */
180 LONG res_query = ERROR_SUCCESS;
183 DWORD maxlen = sizeof(buffer) - 2;
189 if (!pGetAcceptLanguagesA) {
190 win_skip("GetAcceptLanguagesA is not available\n");
194 lcid = GetUserDefaultLCID();
196 /* Get the original Value */
197 lres = RegOpenKeyA(HKEY_CURRENT_USER, ie_international, &hroot);
199 skip("RegOpenKey(%s) failed: %d\n", ie_international, lres);
202 len = sizeof(original);
204 res_query = RegQueryValueExA(hroot, acceptlanguage, 0, NULL, (PBYTE)original, &len);
206 RegDeleteValue(hroot, acceptlanguage);
208 /* Some windows versions use "lang-COUNTRY" as default */
209 memset(language, 0, sizeof(language));
210 len = GetLocaleInfoA(lcid, LOCALE_SISO639LANGNAME, language, sizeof(language));
213 lstrcat(language, "-");
214 memset(buffer, 0, sizeof(buffer));
215 len = GetLocaleInfoA(lcid, LOCALE_SISO3166CTRYNAME, buffer, sizeof(buffer) - len - 1);
216 lstrcat(language, buffer);
220 /* LOCALE_SNAME has additional parts in some languages. Try only as last chance */
221 memset(language, 0, sizeof(language));
222 len = GetLocaleInfoA(lcid, LOCALE_SNAME, language, sizeof(language));
225 /* get the default value */
227 memset(buffer, '#', maxlen);
229 hr = pGetAcceptLanguagesA( buffer, &len);
232 win_skip("GetAcceptLanguagesA failed with 0x%x\n", hr);
233 goto restore_original;
236 if (lstrcmpA(buffer, language)) {
237 /* some windows versions use "lang" or "lang-country" as default */
239 if (pLcidToRfc1766A) {
240 hr = pLcidToRfc1766A(lcid, language, sizeof(language));
241 ok(hr == S_OK, "LcidToRfc1766A returned 0x%x and %s\n", hr, language);
245 ok(!lstrcmpA(buffer, language),
246 "have '%s' (searching for '%s')\n", language, buffer);
248 if (lstrcmpA(buffer, language)) {
249 win_skip("no more ideas, how to build the default language '%s'\n", buffer);
250 goto restore_original;
253 trace("detected default: %s\n", language);
254 while ((entry = table[i])) {
256 exactsize = lstrlenA(entry);
258 lres = RegSetValueExA(hroot, acceptlanguage, 0, REG_SZ, (const BYTE *) entry, exactsize + 1);
259 ok(!lres, "got %d for RegSetValueExA: %s\n", lres, entry);
261 /* len includes space for the terminating 0 before vista/w2k8 */
263 memset(buffer, '#', maxlen);
265 hr = pGetAcceptLanguagesA( buffer, &len);
266 ok(((hr == E_INVALIDARG) && (len == 0)) ||
268 ((len == exactsize) || (len == exactsize+1)) &&
269 !lstrcmpA(buffer, entry)),
270 "+2_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
273 memset(buffer, '#', maxlen);
275 hr = pGetAcceptLanguagesA( buffer, &len);
276 ok(((hr == E_INVALIDARG) && (len == 0)) ||
278 ((len == exactsize) || (len == exactsize+1)) &&
279 !lstrcmpA(buffer, entry)),
280 "+1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
283 memset(buffer, '#', maxlen);
285 hr = pGetAcceptLanguagesA( buffer, &len);
287 /* There is no space for the string in the registry.
288 When the buffer is large enough, the default language is returned
290 When the buffer is too small for that fallback, win7_32 and w2k8_64
291 and above fail with HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), but
292 recent os succeed and return a partial result while
293 older os succeed and overflow the buffer */
295 ok(((hr == E_INVALIDARG) && (len == 0)) ||
296 (((hr == S_OK) && !lstrcmpA(buffer, language) && (len == lstrlenA(language))) ||
297 ((hr == S_OK) && !memcmp(buffer, language, len)) ||
298 ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len)),
299 "==_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
303 memset(buffer, '#', maxlen);
305 hr = pGetAcceptLanguagesA( buffer, &len);
306 ok(((hr == E_INVALIDARG) && (len == 0)) ||
307 (((hr == S_OK) && !lstrcmpA(buffer, language) && (len == lstrlenA(language))) ||
308 ((hr == S_OK) && !memcmp(buffer, language, len)) ||
309 ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len)),
310 "-1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
314 memset(buffer, '#', maxlen);
316 hr = pGetAcceptLanguagesA( buffer, &len);
317 ok(((hr == E_INVALIDARG) && (len == 0)) ||
318 (((hr == S_OK) && !lstrcmpA(buffer, language) && (len == lstrlenA(language))) ||
319 ((hr == S_OK) && !memcmp(buffer, language, len)) ||
320 ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len)),
321 "=1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
324 hr = pGetAcceptLanguagesA( NULL, &len);
326 /* w2k3 and below: E_FAIL and untouched len,
327 since w2k8: S_OK and needed size (excluding 0) */
328 ok( ((hr == S_OK) && (len == exactsize)) ||
329 ((hr == E_FAIL) && (len == maxlen)),
330 "NULL,max #%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
335 /* without a value in the registry, a default language is returned */
336 RegDeleteValue(hroot, acceptlanguage);
339 memset(buffer, '#', maxlen);
341 hr = pGetAcceptLanguagesA( buffer, &len);
342 ok( ((hr == S_OK) && (len == lstrlenA(language))),
343 "max: got 0x%x with %d and %s (expected S_OK with %d and '%s'\n",
344 hr, len, buffer, lstrlenA(language), language);
347 memset(buffer, '#', maxlen);
349 hr = pGetAcceptLanguagesA( buffer, &len);
350 ok( (((hr == S_OK) || (hr == E_INVALIDARG)) && !memcmp(buffer, language, len)) ||
351 ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len),
352 "=2: got 0x%x with %d and %s\n", hr, len, buffer);
355 memset(buffer, '#', maxlen);
357 hr = pGetAcceptLanguagesA( buffer, &len);
358 /* When the buffer is too small, win7_32 and w2k8_64 and above fail with
359 HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), other versions suceed
360 and return a partial 0 terminated result while other versions
361 fail with E_INVALIDARG and return a partial unterminated result */
362 ok( (((hr == S_OK) || (hr == E_INVALIDARG)) && !memcmp(buffer, language, len)) ||
363 ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len),
364 "=1: got 0x%x with %d and %s\n", hr, len, buffer);
367 memset(buffer, '#', maxlen);
369 hr = pGetAcceptLanguagesA( buffer, &len);
370 /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG */
371 ok((hr == E_FAIL) || (hr == E_INVALIDARG),
372 "got 0x%x (expected E_FAIL or E_INVALIDARG)\n", hr);
374 memset(buffer, '#', maxlen);
376 hr = pGetAcceptLanguagesA( buffer, NULL);
377 /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG */
378 ok((hr == E_FAIL) || (hr == E_INVALIDARG),
379 "got 0x%x (expected E_FAIL or E_INVALIDARG)\n", hr);
382 hr = pGetAcceptLanguagesA( NULL, NULL);
383 /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG */
384 ok((hr == E_FAIL) || (hr == E_INVALIDARG),
385 "got 0x%x (expected E_FAIL or E_INVALIDARG)\n", hr);
389 len = lstrlenA(original);
390 lres = RegSetValueExA(hroot, acceptlanguage, 0, REG_SZ, (const BYTE *) original, len ? len + 1: 0);
391 ok(!lres, "RegSetValueEx(%s) failed: %d\n", original, lres);
395 RegDeleteValue(hroot, acceptlanguage);
400 static void test_SHSearchMapInt(void)
402 int keys[8], values[8];
405 if (!pSHSearchMapInt)
408 memset(keys, 0, sizeof(keys));
409 memset(values, 0, sizeof(values));
410 keys[0] = 99; values[0] = 101;
412 /* NULL key/value lists crash native, so skip testing them */
415 i = pSHSearchMapInt(keys, values, 1, keys[0]);
416 ok(i == values[0], "Len 1, expected %d, got %d\n", values[0], i);
418 /* Key doesn't exist */
419 i = pSHSearchMapInt(keys, values, 1, 100);
420 ok(i == -1, "Len 1 - bad key, expected -1, got %d\n", i);
422 /* Len = 0 => not found */
423 i = pSHSearchMapInt(keys, values, 0, keys[0]);
424 ok(i == -1, "Len 1 - passed len 0, expected -1, got %d\n", i);
426 /* 2 elements, len = 1 */
427 keys[1] = 98; values[1] = 102;
428 i = pSHSearchMapInt(keys, values, 1, keys[1]);
429 ok(i == -1, "Len 1 - array len 2, expected -1, got %d\n", i);
431 /* 2 elements, len = 2 */
432 i = pSHSearchMapInt(keys, values, 2, keys[1]);
433 ok(i == values[1], "Len 2, expected %d, got %d\n", values[1], i);
435 /* Searches forward */
436 keys[2] = 99; values[2] = 103;
437 i = pSHSearchMapInt(keys, values, 3, keys[0]);
438 ok(i == values[0], "Len 3, expected %d, got %d\n", values[0], i);
441 static void test_alloc_shared(void)
449 procid=GetCurrentProcessId();
450 hmem=pSHAllocShared(NULL,10,procid);
451 ok(hmem!=NULL,"SHAllocShared(NULL...) failed: %u\n", GetLastError());
452 ret = pSHFreeShared(hmem, procid);
453 ok( ret, "SHFreeShared failed: %u\n", GetLastError());
456 hmem=pSHAllocShared(&val,4,procid);
457 ok(hmem!=NULL,"SHAllocShared(NULL...) failed: %u\n", GetLastError());
459 p=pSHLockShared(hmem,procid);
460 ok(p!=NULL,"SHLockShared failed: %u\n", GetLastError());
462 ok(*p==val,"Wrong value in shared memory: %d instead of %d\n",*p,val);
463 ret = pSHUnlockShared(p);
464 ok( ret, "SHUnlockShared failed: %u\n", GetLastError());
466 ret = pSHFreeShared(hmem, procid);
467 ok( ret, "SHFreeShared failed: %u\n", GetLastError());
470 static void test_fdsa(void)
474 DWORD num_items; /* Number of elements inserted */
475 void *mem; /* Ptr to array */
476 DWORD blocks_alloced; /* Number of elements allocated */
477 BYTE inc; /* Number of elements to grow by when we need to expand */
478 BYTE block_size; /* Size in bytes of an element */
479 BYTE flags; /* Flags */
482 BOOL (WINAPI *pFDSA_Initialize)(DWORD block_size, DWORD inc, FDSA_info *info, void *mem,
484 BOOL (WINAPI *pFDSA_Destroy)(FDSA_info *info);
485 DWORD (WINAPI *pFDSA_InsertItem)(FDSA_info *info, DWORD where, const void *block);
486 BOOL (WINAPI *pFDSA_DeleteItem)(FDSA_info *info, DWORD where);
489 int block_size = 10, init_blocks = 4, inc = 2;
493 pFDSA_Initialize = (void *)GetProcAddress(hShlwapi, (LPSTR)208);
494 pFDSA_Destroy = (void *)GetProcAddress(hShlwapi, (LPSTR)209);
495 pFDSA_InsertItem = (void *)GetProcAddress(hShlwapi, (LPSTR)210);
496 pFDSA_DeleteItem = (void *)GetProcAddress(hShlwapi, (LPSTR)211);
498 mem = HeapAlloc(GetProcessHeap(), 0, block_size * init_blocks);
499 memset(&info, 0, sizeof(info));
501 ok(pFDSA_Initialize(block_size, inc, &info, mem, init_blocks), "FDSA_Initialize rets FALSE\n");
502 ok(info.num_items == 0, "num_items = %d\n", info.num_items);
503 ok(info.mem == mem, "mem = %p\n", info.mem);
504 ok(info.blocks_alloced == init_blocks, "blocks_alloced = %d\n", info.blocks_alloced);
505 ok(info.inc == inc, "inc = %d\n", info.inc);
506 ok(info.block_size == block_size, "block_size = %d\n", info.block_size);
507 ok(info.flags == 0, "flags = %d\n", info.flags);
509 ret = pFDSA_InsertItem(&info, 1234, "1234567890");
510 ok(ret == 0, "ret = %d\n", ret);
511 ok(info.num_items == 1, "num_items = %d\n", info.num_items);
512 ok(info.mem == mem, "mem = %p\n", info.mem);
513 ok(info.blocks_alloced == init_blocks, "blocks_alloced = %d\n", info.blocks_alloced);
514 ok(info.inc == inc, "inc = %d\n", info.inc);
515 ok(info.block_size == block_size, "block_size = %d\n", info.block_size);
516 ok(info.flags == 0, "flags = %d\n", info.flags);
518 ret = pFDSA_InsertItem(&info, 1234, "abcdefghij");
519 ok(ret == 1, "ret = %d\n", ret);
521 ret = pFDSA_InsertItem(&info, 1, "klmnopqrst");
522 ok(ret == 1, "ret = %d\n", ret);
524 ret = pFDSA_InsertItem(&info, 0, "uvwxyzABCD");
525 ok(ret == 0, "ret = %d\n", ret);
526 ok(info.mem == mem, "mem = %p\n", info.mem);
527 ok(info.flags == 0, "flags = %d\n", info.flags);
529 /* This next InsertItem will cause shlwapi to allocate its own mem buffer */
530 ret = pFDSA_InsertItem(&info, 0, "EFGHIJKLMN");
531 ok(ret == 0, "ret = %d\n", ret);
532 ok(info.mem != mem, "mem = %p\n", info.mem);
533 ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %d\n", info.blocks_alloced);
534 ok(info.flags == 0x1, "flags = %d\n", info.flags);
536 ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCD1234567890klmnopqrstabcdefghij", 50), "mem %s\n", (char*)info.mem);
538 ok(pFDSA_DeleteItem(&info, 2), "rets FALSE\n");
539 ok(info.mem != mem, "mem = %p\n", info.mem);
540 ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %d\n", info.blocks_alloced);
541 ok(info.flags == 0x1, "flags = %d\n", info.flags);
543 ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCDklmnopqrstabcdefghij", 40), "mem %s\n", (char*)info.mem);
545 ok(pFDSA_DeleteItem(&info, 3), "rets FALSE\n");
546 ok(info.mem != mem, "mem = %p\n", info.mem);
547 ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %d\n", info.blocks_alloced);
548 ok(info.flags == 0x1, "flags = %d\n", info.flags);
550 ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCDklmnopqrst", 30), "mem %s\n", (char*)info.mem);
552 ok(!pFDSA_DeleteItem(&info, 4), "does not ret FALSE\n");
554 /* As shlwapi has allocated memory internally, Destroy will ret FALSE */
555 ok(!pFDSA_Destroy(&info), "FDSA_Destroy does not ret FALSE\n");
558 /* When Initialize is called with inc = 0, set it to 1 */
559 ok(pFDSA_Initialize(block_size, 0, &info, mem, init_blocks), "FDSA_Initialize rets FALSE\n");
560 ok(info.inc == 1, "inc = %d\n", info.inc);
562 /* This time, because shlwapi hasn't had to allocate memory
563 internally, Destroy rets non-zero */
564 ok(pFDSA_Destroy(&info), "FDSA_Destroy rets FALSE\n");
567 HeapFree(GetProcessHeap(), 0, mem);
571 typedef struct SHELL_USER_SID {
572 SID_IDENTIFIER_AUTHORITY sidAuthority;
575 } SHELL_USER_SID, *PSHELL_USER_SID;
576 typedef struct SHELL_USER_PERMISSION {
577 SHELL_USER_SID susID;
582 DWORD dwInheritAccessMask;
583 } SHELL_USER_PERMISSION, *PSHELL_USER_PERMISSION;
584 static void test_GetShellSecurityDescriptor(void)
586 SHELL_USER_PERMISSION supCurrentUserFull = {
587 { {SECURITY_NULL_SID_AUTHORITY}, 0, 0 },
588 ACCESS_ALLOWED_ACE_TYPE, FALSE,
590 #define MY_INHERITANCE 0xBE /* invalid value to proof behavior */
591 SHELL_USER_PERMISSION supEveryoneDenied = {
592 { {SECURITY_WORLD_SID_AUTHORITY}, SECURITY_WORLD_RID, 0 },
593 ACCESS_DENIED_ACE_TYPE, TRUE,
594 GENERIC_WRITE, MY_INHERITANCE | 0xDEADBA00, GENERIC_READ };
595 PSHELL_USER_PERMISSION rgsup[2] = {
596 &supCurrentUserFull, &supEveryoneDenied,
598 SECURITY_DESCRIPTOR* psd;
599 SECURITY_DESCRIPTOR* (WINAPI*pGetShellSecurityDescriptor)(PSHELL_USER_PERMISSION*,int);
600 void *pChrCmpIW = GetProcAddress(hShlwapi, "ChrCmpIW");
602 pGetShellSecurityDescriptor=(void*)GetProcAddress(hShlwapi,(char*)475);
604 if(!pGetShellSecurityDescriptor)
606 win_skip("GetShellSecurityDescriptor not available\n");
610 if(pChrCmpIW && pChrCmpIW == pGetShellSecurityDescriptor) /* win2k */
612 win_skip("Skipping for GetShellSecurityDescriptor, same ordinal used for ChrCmpIW\n");
616 psd = pGetShellSecurityDescriptor(NULL, 2);
618 broken(psd==INVALID_HANDLE_VALUE), /* IE5 */
619 "GetShellSecurityDescriptor should fail\n");
620 psd = pGetShellSecurityDescriptor(rgsup, 0);
621 ok(psd==NULL, "GetShellSecurityDescriptor should fail, got %p\n", psd);
623 SetLastError(0xdeadbeef);
624 psd = pGetShellSecurityDescriptor(rgsup, 2);
625 if (psd == NULL && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
627 /* The previous calls to GetShellSecurityDescriptor don't set the last error */
628 win_skip("GetShellSecurityDescriptor is not implemented\n");
631 if (psd == INVALID_HANDLE_VALUE)
633 win_skip("GetShellSecurityDescriptor is broken on IE5\n");
636 ok(psd!=NULL, "GetShellSecurityDescriptor failed\n");
639 BOOL bHasDacl = FALSE, bDefaulted;
642 SECURITY_DESCRIPTOR_CONTROL control;
644 ok(IsValidSecurityDescriptor(psd), "returned value is not valid SD\n");
646 ok(GetSecurityDescriptorControl(psd, &control, &dwRev),
647 "GetSecurityDescriptorControl failed with error %u\n", GetLastError());
648 ok(0 == (control & SE_SELF_RELATIVE), "SD should be absolute\n");
650 ok(GetSecurityDescriptorDacl(psd, &bHasDacl, &pAcl, &bDefaulted),
651 "GetSecurityDescriptorDacl failed with error %u\n", GetLastError());
653 ok(bHasDacl, "SD has no DACL\n");
656 ok(!bDefaulted, "DACL should not be defaulted\n");
658 ok(pAcl != NULL, "NULL DACL!\n");
661 ACL_SIZE_INFORMATION asiSize;
663 ok(IsValidAcl(pAcl), "DACL is not valid\n");
665 ok(GetAclInformation(pAcl, &asiSize, sizeof(asiSize), AclSizeInformation),
666 "GetAclInformation failed with error %u\n", GetLastError());
668 ok(asiSize.AceCount == 3, "Incorrect number of ACEs: %d entries\n", asiSize.AceCount);
669 if (asiSize.AceCount == 3)
671 ACCESS_ALLOWED_ACE *paaa; /* will use for DENIED too */
673 ok(GetAce(pAcl, 0, (LPVOID*)&paaa), "GetAce failed with error %u\n", GetLastError());
674 ok(paaa->Header.AceType == ACCESS_ALLOWED_ACE_TYPE,
675 "Invalid ACE type %d\n", paaa->Header.AceType);
676 ok(paaa->Header.AceFlags == 0, "Invalid ACE flags %x\n", paaa->Header.AceFlags);
677 ok(paaa->Mask == GENERIC_ALL, "Invalid ACE mask %x\n", paaa->Mask);
679 ok(GetAce(pAcl, 1, (LPVOID*)&paaa), "GetAce failed with error %u\n", GetLastError());
680 ok(paaa->Header.AceType == ACCESS_DENIED_ACE_TYPE,
681 "Invalid ACE type %d\n", paaa->Header.AceType);
682 /* first one of two ACEs generated from inheritable entry - without inheritance */
683 ok(paaa->Header.AceFlags == 0, "Invalid ACE flags %x\n", paaa->Header.AceFlags);
684 ok(paaa->Mask == GENERIC_WRITE, "Invalid ACE mask %x\n", paaa->Mask);
686 ok(GetAce(pAcl, 2, (LPVOID*)&paaa), "GetAce failed with error %u\n", GetLastError());
687 ok(paaa->Header.AceType == ACCESS_DENIED_ACE_TYPE,
688 "Invalid ACE type %d\n", paaa->Header.AceType);
689 /* second ACE - with inheritance */
690 ok(paaa->Header.AceFlags == MY_INHERITANCE,
691 "Invalid ACE flags %x\n", paaa->Header.AceFlags);
692 ok(paaa->Mask == GENERIC_READ, "Invalid ACE mask %x\n", paaa->Mask);
701 static void test_SHPackDispParams(void)
707 if(!pSHPackDispParams)
708 win_skip("SHPackSidpParams not available\n");
710 memset(¶ms, 0xc0, sizeof(params));
711 memset(vars, 0xc0, sizeof(vars));
712 hres = pSHPackDispParams(¶ms, vars, 1, VT_I4, 0xdeadbeef);
713 ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres);
714 ok(params.cArgs == 1, "params.cArgs = %d\n", params.cArgs);
715 ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
716 ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
717 ok(params.rgvarg == vars, "params.rgvarg = %p\n", params.rgvarg);
718 ok(V_VT(vars) == VT_I4, "V_VT(var) = %d\n", V_VT(vars));
719 ok(V_I4(vars) == 0xdeadbeef, "failed %x\n", V_I4(vars));
721 memset(¶ms, 0xc0, sizeof(params));
722 hres = pSHPackDispParams(¶ms, NULL, 0, 0);
723 ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres);
724 ok(params.cArgs == 0, "params.cArgs = %d\n", params.cArgs);
725 ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
726 ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
727 ok(params.rgvarg == NULL, "params.rgvarg = %p\n", params.rgvarg);
729 memset(vars, 0xc0, sizeof(vars));
730 memset(¶ms, 0xc0, sizeof(params));
731 hres = pSHPackDispParams(¶ms, vars, 4, VT_BSTR, (void*)0xdeadbeef, VT_EMPTY, 10,
732 VT_I4, 100, VT_DISPATCH, (void*)0xdeadbeef);
733 ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres);
734 ok(params.cArgs == 4, "params.cArgs = %d\n", params.cArgs);
735 ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
736 ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
737 ok(params.rgvarg == vars, "params.rgvarg = %p\n", params.rgvarg);
738 ok(V_VT(vars) == VT_DISPATCH, "V_VT(vars[0]) = %x\n", V_VT(vars));
739 ok(V_I4(vars) == 0xdeadbeef, "V_I4(vars[0]) = %x\n", V_I4(vars));
740 ok(V_VT(vars+1) == VT_I4, "V_VT(vars[1]) = %d\n", V_VT(vars+1));
741 ok(V_I4(vars+1) == 100, "V_I4(vars[1]) = %x\n", V_I4(vars+1));
742 ok(V_VT(vars+2) == VT_I4, "V_VT(vars[2]) = %d\n", V_VT(vars+2));
743 ok(V_I4(vars+2) == 10, "V_I4(vars[2]) = %x\n", V_I4(vars+2));
744 ok(V_VT(vars+3) == VT_BSTR, "V_VT(vars[3]) = %d\n", V_VT(vars+3));
745 ok(V_BSTR(vars+3) == (void*)0xdeadbeef, "V_BSTR(vars[3]) = %p\n", V_BSTR(vars+3));
750 IDispatch IDispatch_iface;
754 static inline Disp *impl_from_IDispatch(IDispatch *iface)
756 return CONTAINING_RECORD(iface, Disp, IDispatch_iface);
759 typedef struct _contain
761 IConnectionPointContainer IConnectionPointContainer_iface;
765 IConnectionPoint **pt;
768 static inline Contain *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
770 return CONTAINING_RECORD(iface, Contain, IConnectionPointContainer_iface);
773 typedef struct _cntptn
775 IConnectionPoint IConnectionPoint_iface;
784 static inline ConPt *impl_from_IConnectionPoint(IConnectionPoint *iface)
786 return CONTAINING_RECORD(iface, ConPt, IConnectionPoint_iface);
791 IEnumConnections IEnumConnections_iface;
798 static inline EnumCon *impl_from_IEnumConnections(IEnumConnections *iface)
800 return CONTAINING_RECORD(iface, EnumCon, IEnumConnections_iface);
803 typedef struct _enumpt
805 IEnumConnectionPoints IEnumConnectionPoints_iface;
812 static inline EnumPt *impl_from_IEnumConnectionPoints(IEnumConnectionPoints *iface)
814 return CONTAINING_RECORD(iface, EnumPt, IEnumConnectionPoints_iface);
818 static HRESULT WINAPI Disp_QueryInterface(
825 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDispatch))
832 IUnknown_AddRef(This);
836 trace("no interface\n");
837 return E_NOINTERFACE;
840 static ULONG WINAPI Disp_AddRef(IDispatch* This)
842 Disp *iface = impl_from_IDispatch(This);
843 return InterlockedIncrement(&iface->refCount);
846 static ULONG WINAPI Disp_Release(IDispatch* This)
848 Disp *iface = impl_from_IDispatch(This);
851 ret = InterlockedDecrement(&iface->refCount);
853 HeapFree(GetProcessHeap(),0,This);
857 static HRESULT WINAPI Disp_GetTypeInfoCount(
861 return ERROR_SUCCESS;
864 static HRESULT WINAPI Disp_GetTypeInfo(
870 return ERROR_SUCCESS;
873 static HRESULT WINAPI Disp_GetIDsOfNames(
881 return ERROR_SUCCESS;
884 static HRESULT WINAPI Disp_Invoke(
890 DISPPARAMS *pDispParams,
892 EXCEPINFO *pExcepInfo,
895 trace("%p %x %p %x %x %p %p %p %p\n",This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
897 ok(dispIdMember == 0xa0 || dispIdMember == 0xa1, "Unknown dispIdMember\n");
898 ok(pDispParams != NULL, "Invoked with NULL pDispParams\n");
899 ok(wFlags == DISPATCH_METHOD, "Wrong flags %x\n",wFlags);
900 ok(lcid == 0,"Wrong lcid %x\n",lcid);
901 if (dispIdMember == 0xa0)
903 ok(pDispParams->cArgs == 0, "params.cArgs = %d\n", pDispParams->cArgs);
904 ok(pDispParams->cNamedArgs == 0, "params.cNamedArgs = %d\n", pDispParams->cArgs);
905 ok(pDispParams->rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", pDispParams->rgdispidNamedArgs);
906 ok(pDispParams->rgvarg == NULL, "params.rgvarg = %p\n", pDispParams->rgvarg);
908 else if (dispIdMember == 0xa1)
910 ok(pDispParams->cArgs == 2, "params.cArgs = %d\n", pDispParams->cArgs);
911 ok(pDispParams->cNamedArgs == 0, "params.cNamedArgs = %d\n", pDispParams->cArgs);
912 ok(pDispParams->rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", pDispParams->rgdispidNamedArgs);
913 ok(V_VT(pDispParams->rgvarg) == VT_BSTR, "V_VT(var) = %d\n", V_VT(pDispParams->rgvarg));
914 ok(V_I4(pDispParams->rgvarg) == 0xdeadcafe , "failed %p\n", V_BSTR(pDispParams->rgvarg));
915 ok(V_VT(pDispParams->rgvarg+1) == VT_I4, "V_VT(var) = %d\n", V_VT(pDispParams->rgvarg+1));
916 ok(V_I4(pDispParams->rgvarg+1) == 0xdeadbeef, "failed %x\n", V_I4(pDispParams->rgvarg+1));
919 return ERROR_SUCCESS;
922 static const IDispatchVtbl disp_vtbl = {
927 Disp_GetTypeInfoCount,
933 static HRESULT WINAPI Enum_QueryInterface(
934 IEnumConnections* This,
940 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumConnections))
947 IUnknown_AddRef(This);
951 trace("no interface\n");
952 return E_NOINTERFACE;
955 static ULONG WINAPI Enum_AddRef(IEnumConnections* This)
957 EnumCon *iface = impl_from_IEnumConnections(This);
958 return InterlockedIncrement(&iface->refCount);
961 static ULONG WINAPI Enum_Release(IEnumConnections* This)
963 EnumCon *iface = impl_from_IEnumConnections(This);
966 ret = InterlockedDecrement(&iface->refCount);
968 HeapFree(GetProcessHeap(),0,This);
972 static HRESULT WINAPI Enum_Next(
973 IEnumConnections* This,
978 EnumCon *iface = impl_from_IEnumConnections(This);
980 if (cConnections > 0 && iface->idx < iface->pt->sinkCount)
982 rgcd->pUnk = iface->pt->sink[iface->idx];
983 IUnknown_AddRef(iface->pt->sink[iface->idx]);
994 static HRESULT WINAPI Enum_Skip(
995 IEnumConnections* This,
1001 static HRESULT WINAPI Enum_Reset(
1002 IEnumConnections* This)
1007 static HRESULT WINAPI Enum_Clone(
1008 IEnumConnections* This,
1009 IEnumConnections **ppEnum)
1014 static const IEnumConnectionsVtbl enum_vtbl = {
1016 Enum_QueryInterface,
1025 static HRESULT WINAPI ConPt_QueryInterface(
1026 IConnectionPoint* This,
1032 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IConnectionPoint))
1039 IUnknown_AddRef(This);
1043 trace("no interface\n");
1044 return E_NOINTERFACE;
1047 static ULONG WINAPI ConPt_AddRef(
1048 IConnectionPoint* This)
1050 ConPt *iface = impl_from_IConnectionPoint(This);
1051 return InterlockedIncrement(&iface->refCount);
1054 static ULONG WINAPI ConPt_Release(
1055 IConnectionPoint* This)
1057 ConPt *iface = impl_from_IConnectionPoint(This);
1060 ret = InterlockedDecrement(&iface->refCount);
1063 if (iface->sinkCount > 0)
1066 for (i = 0; i < iface->sinkCount; i++)
1069 IUnknown_Release(iface->sink[i]);
1071 HeapFree(GetProcessHeap(),0,iface->sink);
1073 HeapFree(GetProcessHeap(),0,This);
1078 static HRESULT WINAPI ConPt_GetConnectionInterface(
1079 IConnectionPoint* This,
1083 ConPt *iface = impl_from_IConnectionPoint(This);
1090 memcpy(pIID,&iface->id,sizeof(GUID));
1094 static HRESULT WINAPI ConPt_GetConnectionPointContainer(
1095 IConnectionPoint* This,
1096 IConnectionPointContainer **ppCPC)
1098 ConPt *iface = impl_from_IConnectionPoint(This);
1100 *ppCPC = &iface->container->IConnectionPointContainer_iface;
1104 static HRESULT WINAPI ConPt_Advise(
1105 IConnectionPoint* This,
1109 ConPt *iface = impl_from_IConnectionPoint(This);
1111 if (iface->sinkCount == 0)
1112 iface->sink = HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown*));
1114 iface->sink = HeapReAlloc(GetProcessHeap(),0,iface->sink,sizeof(IUnknown*)*(iface->sinkCount+1));
1115 iface->sink[iface->sinkCount] = pUnkSink;
1116 IUnknown_AddRef(pUnkSink);
1118 *pdwCookie = iface->sinkCount;
1122 static HRESULT WINAPI ConPt_Unadvise(
1123 IConnectionPoint* This,
1126 ConPt *iface = impl_from_IConnectionPoint(This);
1128 if (dwCookie > iface->sinkCount)
1132 IUnknown_Release(iface->sink[dwCookie-1]);
1133 iface->sink[dwCookie-1] = NULL;
1138 static HRESULT WINAPI ConPt_EnumConnections(
1139 IConnectionPoint* This,
1140 IEnumConnections **ppEnum)
1144 ec = HeapAlloc(GetProcessHeap(),0,sizeof(EnumCon));
1145 ec->IEnumConnections_iface.lpVtbl = &enum_vtbl;
1147 ec->pt = impl_from_IConnectionPoint(This);
1149 *ppEnum = &ec->IEnumConnections_iface;
1154 static const IConnectionPointVtbl point_vtbl = {
1155 ConPt_QueryInterface,
1159 ConPt_GetConnectionInterface,
1160 ConPt_GetConnectionPointContainer,
1163 ConPt_EnumConnections
1166 static HRESULT WINAPI EnumPt_QueryInterface(
1167 IEnumConnectionPoints* This,
1173 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumConnectionPoints))
1180 IUnknown_AddRef(This);
1184 trace("no interface\n");
1185 return E_NOINTERFACE;
1188 static ULONG WINAPI EnumPt_AddRef(IEnumConnectionPoints* This)
1190 EnumPt *iface = impl_from_IEnumConnectionPoints(This);
1191 return InterlockedIncrement(&iface->refCount);
1194 static ULONG WINAPI EnumPt_Release(IEnumConnectionPoints* This)
1196 EnumPt *iface = impl_from_IEnumConnectionPoints(This);
1199 ret = InterlockedDecrement(&iface->refCount);
1201 HeapFree(GetProcessHeap(),0,This);
1205 static HRESULT WINAPI EnumPt_Next(
1206 IEnumConnectionPoints* This,
1208 IConnectionPoint **rgcd,
1211 EnumPt *iface = impl_from_IEnumConnectionPoints(This);
1213 if (cConnections > 0 && iface->idx < iface->container->ptCount)
1215 *rgcd = iface->container->pt[iface->idx];
1216 IUnknown_AddRef(iface->container->pt[iface->idx]);
1226 static HRESULT WINAPI EnumPt_Skip(
1227 IEnumConnectionPoints* This,
1233 static HRESULT WINAPI EnumPt_Reset(
1234 IEnumConnectionPoints* This)
1239 static HRESULT WINAPI EnumPt_Clone(
1240 IEnumConnectionPoints* This,
1241 IEnumConnectionPoints **ppEnumPt)
1246 static const IEnumConnectionPointsVtbl enumpt_vtbl = {
1248 EnumPt_QueryInterface,
1257 static HRESULT WINAPI Contain_QueryInterface(
1258 IConnectionPointContainer* This,
1264 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IConnectionPointContainer))
1271 IUnknown_AddRef(This);
1275 trace("no interface\n");
1276 return E_NOINTERFACE;
1279 static ULONG WINAPI Contain_AddRef(
1280 IConnectionPointContainer* This)
1282 Contain *iface = impl_from_IConnectionPointContainer(This);
1283 return InterlockedIncrement(&iface->refCount);
1286 static ULONG WINAPI Contain_Release(
1287 IConnectionPointContainer* This)
1289 Contain *iface = impl_from_IConnectionPointContainer(This);
1292 ret = InterlockedDecrement(&iface->refCount);
1295 if (iface->ptCount > 0)
1298 for (i = 0; i < iface->ptCount; i++)
1299 IUnknown_Release(iface->pt[i]);
1300 HeapFree(GetProcessHeap(),0,iface->pt);
1302 HeapFree(GetProcessHeap(),0,This);
1307 static HRESULT WINAPI Contain_EnumConnectionPoints(
1308 IConnectionPointContainer* This,
1309 IEnumConnectionPoints **ppEnum)
1313 ec = HeapAlloc(GetProcessHeap(),0,sizeof(EnumPt));
1314 ec->IEnumConnectionPoints_iface.lpVtbl = &enumpt_vtbl;
1317 ec->container = impl_from_IConnectionPointContainer(This);
1318 *ppEnum = &ec->IEnumConnectionPoints_iface;
1323 static HRESULT WINAPI Contain_FindConnectionPoint(
1324 IConnectionPointContainer* This,
1326 IConnectionPoint **ppCP)
1328 Contain *iface = impl_from_IConnectionPointContainer(This);
1331 if (!IsEqualIID(riid, &IID_NULL) || iface->ptCount ==0)
1333 pt = HeapAlloc(GetProcessHeap(),0,sizeof(ConPt));
1334 pt->IConnectionPoint_iface.lpVtbl = &point_vtbl;
1338 pt->container = iface;
1339 pt->id = IID_IDispatch;
1341 if (iface->ptCount == 0)
1342 iface->pt =HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown*));
1344 iface->pt = HeapReAlloc(GetProcessHeap(),0,iface->pt,sizeof(IUnknown*)*(iface->ptCount+1));
1345 iface->pt[iface->ptCount] = &pt->IConnectionPoint_iface;
1348 *ppCP = &pt->IConnectionPoint_iface;
1352 *ppCP = iface->pt[0];
1353 IUnknown_AddRef((IUnknown*)*ppCP);
1359 static const IConnectionPointContainerVtbl contain_vtbl = {
1360 Contain_QueryInterface,
1364 Contain_EnumConnectionPoints,
1365 Contain_FindConnectionPoint
1368 static void test_IConnectionPoint(void)
1372 IConnectionPoint *point;
1375 DWORD cookie = 0xffffffff;
1379 if (!pIConnectionPoint_SimpleInvoke || !pConnectToConnectionPoint)
1381 win_skip("IConnectionPoint Apis not present\n");
1385 container = HeapAlloc(GetProcessHeap(),0,sizeof(Contain));
1386 container->IConnectionPointContainer_iface.lpVtbl = &contain_vtbl;
1387 container->refCount = 1;
1388 container->ptCount = 0;
1389 container->pt = NULL;
1391 dispatch = HeapAlloc(GetProcessHeap(),0,sizeof(Disp));
1392 dispatch->IDispatch_iface.lpVtbl = &disp_vtbl;
1393 dispatch->refCount = 1;
1395 rc = pConnectToConnectionPoint((IUnknown*)dispatch, &IID_NULL, TRUE, (IUnknown*)container, &cookie, &point);
1396 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1397 ok(point != NULL, "returned ConnectionPoint is NULL\n");
1398 ok(cookie != 0xffffffff, "invalid cookie returned\n");
1400 rc = pIConnectionPoint_SimpleInvoke(point,0xa0,NULL);
1401 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1403 if (pSHPackDispParams)
1405 memset(¶ms, 0xc0, sizeof(params));
1406 memset(vars, 0xc0, sizeof(vars));
1407 rc = pSHPackDispParams(¶ms, vars, 2, VT_I4, 0xdeadbeef, VT_BSTR, 0xdeadcafe);
1408 ok(rc == S_OK, "SHPackDispParams failed: %08x\n", rc);
1410 rc = pIConnectionPoint_SimpleInvoke(point,0xa1,¶ms);
1411 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1414 win_skip("pSHPackDispParams not present\n");
1416 rc = pConnectToConnectionPoint(NULL, &IID_NULL, FALSE, (IUnknown*)container, &cookie, NULL);
1417 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1419 /* MSDN says this should be required but it crashs on XP
1420 IUnknown_Release(point);
1422 ref = IUnknown_Release((IUnknown*)container);
1423 ok(ref == 0, "leftover IConnectionPointContainer reference %i\n",ref);
1424 ref = IUnknown_Release((IUnknown*)dispatch);
1425 ok(ref == 0, "leftover IDispatch reference %i\n",ref);
1428 typedef struct _propbag
1430 IPropertyBag IPropertyBag_iface;
1435 static inline PropBag *impl_from_IPropertyBag(IPropertyBag *iface)
1437 return CONTAINING_RECORD(iface, PropBag, IPropertyBag_iface);
1441 static HRESULT WINAPI Prop_QueryInterface(
1448 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPropertyBag))
1455 IUnknown_AddRef(This);
1459 trace("no interface\n");
1460 return E_NOINTERFACE;
1463 static ULONG WINAPI Prop_AddRef(
1466 PropBag *iface = impl_from_IPropertyBag(This);
1467 return InterlockedIncrement(&iface->refCount);
1470 static ULONG WINAPI Prop_Release(
1473 PropBag *iface = impl_from_IPropertyBag(This);
1476 ret = InterlockedDecrement(&iface->refCount);
1478 HeapFree(GetProcessHeap(),0,This);
1482 static HRESULT WINAPI Prop_Read(
1484 LPCOLESTR pszPropName,
1486 IErrorLog *pErrorLog)
1488 V_VT(pVar) = VT_BLOB|VT_BYREF;
1489 V_BYREF(pVar) = (LPVOID)0xdeadcafe;
1493 static HRESULT WINAPI Prop_Write(
1495 LPCOLESTR pszPropName,
1502 static const IPropertyBagVtbl prop_vtbl = {
1503 Prop_QueryInterface,
1511 static void test_SHPropertyBag_ReadLONG(void)
1516 static const WCHAR szName1[] = {'n','a','m','e','1',0};
1518 if (!pSHPropertyBag_ReadLONG)
1520 win_skip("SHPropertyBag_ReadLONG not present\n");
1524 pb = HeapAlloc(GetProcessHeap(),0,sizeof(PropBag));
1526 pb->IPropertyBag_iface.lpVtbl = &prop_vtbl;
1529 rc = pSHPropertyBag_ReadLONG(NULL, szName1, &out);
1530 ok(rc == E_INVALIDARG || broken(rc == 0), "incorrect return %x\n",rc);
1531 ok(out == 0xfeedface, "value should not have changed\n");
1532 rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, NULL, &out);
1533 ok(rc == E_INVALIDARG || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
1534 ok(out == 0xfeedface, "value should not have changed\n");
1535 rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, szName1, NULL);
1536 ok(rc == E_INVALIDARG || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
1537 ok(out == 0xfeedface, "value should not have changed\n");
1538 rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, szName1, &out);
1539 ok(rc == DISP_E_BADVARTYPE || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
1540 ok(out == 0xfeedface || broken(out == 0xfeedfa00), "value should not have changed %x\n",out);
1541 IUnknown_Release((IUnknown*)pb);
1546 static void test_SHSetWindowBits(void)
1549 DWORD style, styleold;
1552 if(!pSHSetWindowBits)
1554 win_skip("SHSetWindowBits is not available\n");
1559 clsA.lpfnWndProc = DefWindowProcA;
1560 clsA.cbClsExtra = 0;
1561 clsA.cbWndExtra = 0;
1562 clsA.hInstance = GetModuleHandleA(NULL);
1564 clsA.hCursor = LoadCursorA(0, IDC_ARROW);
1565 clsA.hbrBackground = NULL;
1566 clsA.lpszMenuName = NULL;
1567 clsA.lpszClassName = "Shlwapi test class";
1568 RegisterClassA(&clsA);
1570 hwnd = CreateWindowA("Shlwapi test class", "Test", WS_VISIBLE, 0, 0, 100, 100,
1571 NULL, NULL, GetModuleHandle(NULL), 0);
1572 ok(IsWindow(hwnd), "failed to create window\n");
1575 SetLastError(0xdeadbeef);
1576 style = pSHSetWindowBits(NULL, GWL_STYLE, 0, 0);
1577 ok(style == 0, "expected 0 retval, got %d\n", style);
1578 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
1579 broken(GetLastError() == 0xdeadbeef), /* Win9x/WinMe */
1580 "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
1582 /* zero mask, zero flags */
1583 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1584 style = pSHSetWindowBits(hwnd, GWL_STYLE, 0, 0);
1585 ok(styleold == style, "expected old style\n");
1586 ok(styleold == GetWindowLongA(hwnd, GWL_STYLE), "expected to keep old style\n");
1589 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1590 ok(styleold & WS_VISIBLE, "expected WS_VISIBLE\n");
1591 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1593 ok(style == styleold, "expected previous style, got %x\n", style);
1594 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1596 /* test mask, unset style bit used */
1597 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1598 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1599 ok(style == styleold, "expected previous style, got %x\n", style);
1600 ok(styleold == GetWindowLongA(hwnd, GWL_STYLE), "expected to keep old style\n");
1602 /* set back with flags */
1603 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1604 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, WS_VISIBLE);
1605 ok(style == styleold, "expected previous style, got %x\n", style);
1606 ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "expected updated style\n");
1608 /* reset and try to set without a mask */
1609 pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1610 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1611 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1612 style = pSHSetWindowBits(hwnd, GWL_STYLE, 0, WS_VISIBLE);
1613 ok(style == styleold, "expected previous style, got %x\n", style);
1614 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1616 DestroyWindow(hwnd);
1618 UnregisterClassA("Shlwapi test class", GetModuleHandleA(NULL));
1621 static void test_SHFormatDateTimeA(void)
1623 FILETIME UNALIGNED filetime;
1624 CHAR buff[100], buff2[100], buff3[100];
1629 if(!pSHFormatDateTimeA)
1631 win_skip("pSHFormatDateTimeA isn't available\n");
1637 /* crashes on native */
1638 ret = pSHFormatDateTimeA(NULL, NULL, NULL, 0);
1642 SystemTimeToFileTime(&st, &filetime);
1643 /* SHFormatDateTime expects input as utc */
1644 LocalFileTimeToFileTime(&filetime, &filetime);
1646 /* no way to get required buffer length here */
1647 SetLastError(0xdeadbeef);
1648 ret = pSHFormatDateTimeA(&filetime, NULL, NULL, 0);
1649 ok(ret == 0, "got %d\n", ret);
1650 ok(GetLastError() == 0xdeadbeef || broken(GetLastError() == ERROR_SUCCESS /* Win7 */),
1651 "expected 0xdeadbeef, got %d\n", GetLastError());
1653 SetLastError(0xdeadbeef);
1654 buff[0] = 'a'; buff[1] = 0;
1655 ret = pSHFormatDateTimeA(&filetime, NULL, buff, 0);
1656 ok(ret == 0, "got %d\n", ret);
1657 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1658 ok(buff[0] == 'a', "expected same string, got %s\n", buff);
1660 /* flags needs to have FDTF_NOAUTOREADINGORDER for these tests to succeed on Vista+ */
1662 /* all combinations documented as invalid succeeded */
1663 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTTIME | FDTF_LONGTIME;
1664 SetLastError(0xdeadbeef);
1665 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1666 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1667 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1669 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_LONGDATE;
1670 SetLastError(0xdeadbeef);
1671 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1672 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1673 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1675 flags = FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE;
1676 SetLastError(0xdeadbeef);
1677 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1678 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1679 ok(GetLastError() == 0xdeadbeef ||
1680 broken(GetLastError() == ERROR_INVALID_FLAGS), /* Win9x/WinMe */
1681 "expected 0xdeadbeef, got %d\n", GetLastError());
1683 /* now check returned strings */
1684 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTTIME;
1685 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1686 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1687 ret = GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff2, sizeof(buff2));
1688 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1689 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1691 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGTIME;
1692 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1693 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1694 ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2));
1695 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1696 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1698 /* both time flags */
1699 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGTIME | FDTF_SHORTTIME;
1700 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1701 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1702 ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2));
1703 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1704 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1706 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE;
1707 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1708 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1709 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1710 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1711 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1713 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE;
1714 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1715 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1716 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1717 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1718 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1720 /* both date flags */
1721 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_SHORTDATE;
1722 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1723 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1724 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1725 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1726 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1728 /* various combinations of date/time flags */
1729 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_SHORTTIME;
1730 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1731 ok(ret == lstrlenA(buff)+1, "got %d, length %d\n", ret, lstrlenA(buff)+1);
1732 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1733 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1734 strcat(buff2, ", ");
1735 ret = GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3));
1736 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1737 strcat(buff2, buff3);
1738 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1740 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_LONGTIME;
1741 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1742 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1743 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1744 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1745 strcat(buff2, ", ");
1746 ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3));
1747 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1748 strcat(buff2, buff3);
1749 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1751 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_SHORTTIME;
1752 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1753 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1754 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1755 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1757 ret = GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3));
1758 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1759 strcat(buff2, buff3);
1760 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1762 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_LONGTIME;
1763 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1764 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1765 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1766 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1768 ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3));
1769 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1770 strcat(buff2, buff3);
1771 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1774 static void test_SHFormatDateTimeW(void)
1776 FILETIME UNALIGNED filetime;
1777 WCHAR buff[100], buff2[100], buff3[100];
1781 static const WCHAR spaceW[] = {' ',0};
1782 static const WCHAR commaW[] = {',',' ',0};
1784 if(!pSHFormatDateTimeW)
1786 win_skip("pSHFormatDateTimeW isn't available\n");
1792 /* crashes on native */
1793 ret = pSHFormatDateTimeW(NULL, NULL, NULL, 0);
1797 SystemTimeToFileTime(&st, &filetime);
1798 /* SHFormatDateTime expects input as utc */
1799 LocalFileTimeToFileTime(&filetime, &filetime);
1801 /* no way to get required buffer length here */
1802 SetLastError(0xdeadbeef);
1803 ret = pSHFormatDateTimeW(&filetime, NULL, NULL, 0);
1804 ok(ret == 0, "expected 0, got %d\n", ret);
1805 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1807 SetLastError(0xdeadbeef);
1808 buff[0] = 'a'; buff[1] = 0;
1809 ret = pSHFormatDateTimeW(&filetime, NULL, buff, 0);
1810 ok(ret == 0, "expected 0, got %d\n", ret);
1811 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1812 ok(buff[0] == 'a', "expected same string\n");
1814 /* all combinations documented as invalid succeeded */
1815 flags = FDTF_SHORTTIME | FDTF_LONGTIME;
1816 SetLastError(0xdeadbeef);
1817 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1818 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1819 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1820 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1822 flags = FDTF_SHORTDATE | FDTF_LONGDATE;
1823 SetLastError(0xdeadbeef);
1824 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1825 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1826 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1827 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1829 flags = FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE;
1830 SetLastError(0xdeadbeef);
1831 buff[0] = 0; /* NT4 doesn't clear the buffer on failure */
1832 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1833 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1834 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1835 ok(GetLastError() == 0xdeadbeef ||
1836 broken(GetLastError() == ERROR_INVALID_FLAGS), /* Win9x/WinMe/NT4 */
1837 "expected 0xdeadbeef, got %d\n", GetLastError());
1839 /* now check returned strings */
1840 flags = FDTF_SHORTTIME;
1841 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1842 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1843 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1844 SetLastError(0xdeadbeef);
1845 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1846 if (ret == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1848 win_skip("Needed W-functions are not implemented\n");
1851 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1852 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1854 flags = FDTF_LONGTIME;
1855 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1856 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1857 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1858 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1859 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1860 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1862 /* both time flags */
1863 flags = FDTF_LONGTIME | FDTF_SHORTTIME;
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 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1868 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1869 ok(lstrcmpW(buff, buff2) == 0, "expected equal string\n");
1871 flags = FDTF_SHORTDATE;
1872 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1873 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1874 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1875 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1876 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1877 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1879 flags = FDTF_LONGDATE;
1880 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1881 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1882 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1883 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1884 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1885 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1887 /* both date flags */
1888 flags = FDTF_LONGDATE | FDTF_SHORTDATE;
1889 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1890 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1891 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1892 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1893 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1894 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1896 /* various combinations of date/time flags */
1897 flags = FDTF_LONGDATE | FDTF_SHORTTIME;
1898 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1899 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1900 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1901 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1902 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1903 lstrcatW(buff2, commaW);
1904 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1905 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1906 lstrcatW(buff2, buff3);
1907 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1909 flags = FDTF_LONGDATE | FDTF_LONGTIME;
1910 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1911 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1912 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1913 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1914 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1915 lstrcatW(buff2, commaW);
1916 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1917 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1918 lstrcatW(buff2, buff3);
1919 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1921 flags = FDTF_SHORTDATE | FDTF_SHORTTIME;
1922 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1923 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1924 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1925 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1926 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1927 lstrcatW(buff2, spaceW);
1928 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1929 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1930 lstrcatW(buff2, buff3);
1931 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1933 flags = FDTF_SHORTDATE | FDTF_LONGTIME;
1934 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1935 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1936 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1937 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1938 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1939 lstrcatW(buff2, spaceW);
1940 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1941 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1942 lstrcatW(buff2, buff3);
1943 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1946 static void test_SHGetObjectCompatFlags(void)
1948 struct compat_value {
1953 struct compat_value values[] = {
1954 { "OTNEEDSSFCACHE", 0x1 },
1955 { "NO_WEBVIEW", 0x2 },
1956 { "UNBINDABLE", 0x4 },
1958 { "NEEDSFILESYSANCESTOR", 0x10 },
1959 { "NOTAFILESYSTEM", 0x20 },
1960 { "CTXMENU_NOVERBS", 0x40 },
1961 { "CTXMENU_LIMITEDQI", 0x80 },
1962 { "COCREATESHELLFOLDERONLY", 0x100 },
1963 { "NEEDSSTORAGEANCESTOR", 0x200 },
1964 { "NOLEGACYWEBVIEW", 0x400 },
1965 { "CTXMENU_XPQCMFLAGS", 0x1000 },
1966 { "NOIPROPERTYSTORE", 0x2000 }
1969 static const char compat_path[] = "Software\\Microsoft\\Windows\\CurrentVersion\\ShellCompatibility\\Objects";
1970 void *pColorAdjustLuma = GetProcAddress(hShlwapi, "ColorAdjustLuma");
1971 CHAR keyA[39]; /* {CLSID} */
1976 if (!pSHGetObjectCompatFlags)
1978 win_skip("SHGetObjectCompatFlags isn't available\n");
1982 if (pColorAdjustLuma && pColorAdjustLuma == pSHGetObjectCompatFlags) /* win2k */
1984 win_skip("Skipping SHGetObjectCompatFlags, same ordinal used for ColorAdjustLuma\n");
1989 ret = pSHGetObjectCompatFlags(NULL, NULL);
1990 ok(ret == 0, "got %d\n", ret);
1992 ret = RegOpenKeyA(HKEY_LOCAL_MACHINE, compat_path, &root);
1993 if (ret != ERROR_SUCCESS)
1995 skip("No compatibility class data found\n");
1999 for (i = 0; RegEnumKeyA(root, i, keyA, sizeof(keyA)) == ERROR_SUCCESS; i++)
2003 if (RegOpenKeyA(root, keyA, &clsid_key) == ERROR_SUCCESS)
2006 DWORD expected = 0, got, length = sizeof(valueA);
2010 for (v = 0; RegEnumValueA(clsid_key, v, valueA, &length, NULL, NULL, NULL, NULL) == ERROR_SUCCESS; v++)
2014 for (j = 0; j < sizeof(values)/sizeof(struct compat_value); j++)
2015 if (lstrcmpA(values[j].nameA, valueA) == 0)
2017 expected |= values[j].value;
2021 length = sizeof(valueA);
2024 pGUIDFromStringA(keyA, &clsid);
2025 got = pSHGetObjectCompatFlags(NULL, &clsid);
2026 ok(got == expected, "got 0x%08x, expected 0x%08x. Key %s\n", got, expected, keyA);
2028 RegCloseKey(clsid_key);
2036 const IOleCommandTargetVtbl *lpVtbl;
2038 } IOleCommandTargetImpl;
2040 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl;
2042 static IOleCommandTarget* IOleCommandTargetImpl_Construct(void)
2044 IOleCommandTargetImpl *obj;
2046 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2047 obj->lpVtbl = &IOleCommandTargetImpl_Vtbl;
2050 return (IOleCommandTarget*)obj;
2053 static HRESULT WINAPI IOleCommandTargetImpl_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppvObj)
2055 IOleCommandTargetImpl *This = (IOleCommandTargetImpl *)iface;
2057 if (IsEqualIID(riid, &IID_IUnknown) ||
2058 IsEqualIID(riid, &IID_IOleCommandTarget))
2065 IUnknown_AddRef(iface);
2069 return E_NOINTERFACE;
2072 static ULONG WINAPI IOleCommandTargetImpl_AddRef(IOleCommandTarget *iface)
2074 IOleCommandTargetImpl *This = (IOleCommandTargetImpl *)iface;
2075 return InterlockedIncrement(&This->ref);
2078 static ULONG WINAPI IOleCommandTargetImpl_Release(IOleCommandTarget *iface)
2080 IOleCommandTargetImpl *This = (IOleCommandTargetImpl *)iface;
2081 ULONG ref = InterlockedDecrement(&This->ref);
2085 HeapFree(GetProcessHeap(), 0, This);
2091 static HRESULT WINAPI IOleCommandTargetImpl_QueryStatus(
2092 IOleCommandTarget *iface, const GUID *group, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText)
2097 static HRESULT WINAPI IOleCommandTargetImpl_Exec(
2098 IOleCommandTarget *iface,
2099 const GUID *CmdGroup,
2105 add_call(&trace_got, 3, CmdGroup, (void*)(DWORD_PTR)nCmdID, (void*)(DWORD_PTR)nCmdexecopt, pvaIn, pvaOut);
2109 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl =
2111 IOleCommandTargetImpl_QueryInterface,
2112 IOleCommandTargetImpl_AddRef,
2113 IOleCommandTargetImpl_Release,
2114 IOleCommandTargetImpl_QueryStatus,
2115 IOleCommandTargetImpl_Exec
2119 const IServiceProviderVtbl *lpVtbl;
2121 } IServiceProviderImpl;
2124 const IProfferServiceVtbl *lpVtbl;
2126 } IProfferServiceImpl;
2129 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl;
2130 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl;
2132 static IServiceProvider* IServiceProviderImpl_Construct(void)
2134 IServiceProviderImpl *obj;
2136 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2137 obj->lpVtbl = &IServiceProviderImpl_Vtbl;
2140 return (IServiceProvider*)obj;
2143 static IProfferService* IProfferServiceImpl_Construct(void)
2145 IProfferServiceImpl *obj;
2147 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2148 obj->lpVtbl = &IProfferServiceImpl_Vtbl;
2151 return (IProfferService*)obj;
2154 static HRESULT WINAPI IServiceProviderImpl_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppvObj)
2156 IServiceProviderImpl *This = (IServiceProviderImpl *)iface;
2158 if (IsEqualIID(riid, &IID_IUnknown) ||
2159 IsEqualIID(riid, &IID_IServiceProvider))
2166 IUnknown_AddRef(iface);
2167 /* native uses redefined IID_IServiceProvider symbol, so we can't compare pointers */
2168 if (IsEqualIID(riid, &IID_IServiceProvider))
2169 add_call(&trace_got, 1, iface, &IID_IServiceProvider, 0, 0, 0);
2173 return E_NOINTERFACE;
2176 static ULONG WINAPI IServiceProviderImpl_AddRef(IServiceProvider *iface)
2178 IServiceProviderImpl *This = (IServiceProviderImpl *)iface;
2179 return InterlockedIncrement(&This->ref);
2182 static ULONG WINAPI IServiceProviderImpl_Release(IServiceProvider *iface)
2184 IServiceProviderImpl *This = (IServiceProviderImpl *)iface;
2185 ULONG ref = InterlockedDecrement(&This->ref);
2189 HeapFree(GetProcessHeap(), 0, This);
2195 static HRESULT WINAPI IServiceProviderImpl_QueryService(
2196 IServiceProvider *iface, REFGUID service, REFIID riid, void **ppv)
2198 /* native uses redefined pointer for IID_IOleCommandTarget, not one from uuid.lib */
2199 if (IsEqualIID(riid, &IID_IOleCommandTarget))
2201 add_call(&trace_got, 2, iface, service, &IID_IOleCommandTarget, 0, 0);
2202 *ppv = IOleCommandTargetImpl_Construct();
2204 if (IsEqualIID(riid, &IID_IProfferService))
2206 if (IsEqualIID(service, &IID_IProfferService))
2207 add_call(&trace_got, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2208 *ppv = IProfferServiceImpl_Construct();
2213 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl =
2215 IServiceProviderImpl_QueryInterface,
2216 IServiceProviderImpl_AddRef,
2217 IServiceProviderImpl_Release,
2218 IServiceProviderImpl_QueryService
2221 static void test_IUnknown_QueryServiceExec(void)
2223 IServiceProvider *provider = IServiceProviderImpl_Construct();
2224 static const GUID dummy_serviceid = { 0xdeadbeef };
2225 static const GUID dummy_groupid = { 0xbeefbeef };
2226 call_trace_t trace_expected;
2229 /* on <=W2K platforms same ordinal used for another export with different
2230 prototype, so skipping using this indirect condition */
2231 if (is_win2k_and_lower)
2233 win_skip("IUnknown_QueryServiceExec is not available\n");
2237 /* null source pointer */
2238 hr = pIUnknown_QueryServiceExec(NULL, &dummy_serviceid, &dummy_groupid, 0, 0, 0, 0);
2239 ok(hr == E_FAIL, "got 0x%08x\n", hr);
2242 IUnknown_QueryServiceExec( ptr1, serviceid, groupid, arg1, arg2, arg3, arg4);
2243 -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &prov );
2244 -> IServiceProvider_QueryService( prov, serviceid, &IID_IOleCommandTarget, &obj );
2245 -> IOleCommandTarget_Exec( obj, groupid, arg1, arg2, arg3, arg4 );
2247 init_call_trace(&trace_expected);
2249 add_call(&trace_expected, 1, provider, &IID_IServiceProvider, 0, 0, 0);
2250 add_call(&trace_expected, 2, provider, &dummy_serviceid, &IID_IOleCommandTarget, 0, 0);
2251 add_call(&trace_expected, 3, &dummy_groupid, (void*)0x1, (void*)0x2, (void*)0x3, (void*)0x4);
2253 init_call_trace(&trace_got);
2254 hr = pIUnknown_QueryServiceExec((IUnknown*)provider, &dummy_serviceid, &dummy_groupid, 0x1, 0x2, (void*)0x3, (void*)0x4);
2255 ok(hr == S_OK, "got 0x%08x\n", hr);
2257 ok_trace(&trace_expected, &trace_got);
2259 free_call_trace(&trace_expected);
2260 free_call_trace(&trace_got);
2262 IServiceProvider_Release(provider);
2266 static HRESULT WINAPI IProfferServiceImpl_QueryInterface(IProfferService *iface, REFIID riid, void **ppvObj)
2268 IProfferServiceImpl *This = (IProfferServiceImpl *)iface;
2270 if (IsEqualIID(riid, &IID_IUnknown) ||
2271 IsEqualIID(riid, &IID_IProfferService))
2275 else if (IsEqualIID(riid, &IID_IServiceProvider))
2277 *ppvObj = IServiceProviderImpl_Construct();
2278 add_call(&trace_got, 1, iface, &IID_IServiceProvider, 0, 0, 0);
2284 IUnknown_AddRef(iface);
2288 return E_NOINTERFACE;
2291 static ULONG WINAPI IProfferServiceImpl_AddRef(IProfferService *iface)
2293 IProfferServiceImpl *This = (IProfferServiceImpl *)iface;
2294 return InterlockedIncrement(&This->ref);
2297 static ULONG WINAPI IProfferServiceImpl_Release(IProfferService *iface)
2299 IProfferServiceImpl *This = (IProfferServiceImpl *)iface;
2300 ULONG ref = InterlockedDecrement(&This->ref);
2304 HeapFree(GetProcessHeap(), 0, This);
2310 static HRESULT WINAPI IProfferServiceImpl_ProfferService(IProfferService *iface,
2311 REFGUID service, IServiceProvider *pService, DWORD *pCookie)
2313 add_call(&trace_got, 3, service, pService, pCookie, 0, 0);
2317 static HRESULT WINAPI IProfferServiceImpl_RevokeService(IProfferService *iface, DWORD cookie)
2319 add_call(&trace_got, 4, (void*)(DWORD_PTR)cookie, 0, 0, 0, 0);
2323 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl =
2325 IProfferServiceImpl_QueryInterface,
2326 IProfferServiceImpl_AddRef,
2327 IProfferServiceImpl_Release,
2328 IProfferServiceImpl_ProfferService,
2329 IProfferServiceImpl_RevokeService
2332 static void test_IUnknown_ProfferService(void)
2334 IServiceProvider *provider = IServiceProviderImpl_Construct();
2335 IProfferService *proff = IProfferServiceImpl_Construct();
2336 static const GUID dummy_serviceid = { 0xdeadbeef };
2337 call_trace_t trace_expected;
2341 /* on <=W2K platforms same ordinal used for another export with different
2342 prototype, so skipping using this indirect condition */
2343 if (is_win2k_and_lower)
2345 win_skip("IUnknown_ProfferService is not available\n");
2349 /* null source pointer */
2350 hr = pIUnknown_ProfferService(NULL, &dummy_serviceid, 0, 0);
2351 ok(hr == E_FAIL, "got 0x%08x\n", hr);
2354 IUnknown_ProfferService( ptr1, serviceid, arg1, arg2);
2355 -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &provider );
2356 -> IServiceProvider_QueryService( provider, &IID_IProfferService, &IID_IProfferService, &proffer );
2358 if (service pointer not null):
2359 -> IProfferService_ProfferService( proffer, serviceid, arg1, arg2 );
2361 -> IProfferService_RevokeService( proffer, *arg2 );
2363 init_call_trace(&trace_expected);
2365 add_call(&trace_expected, 1, proff, &IID_IServiceProvider, 0, 0, 0);
2366 add_call(&trace_expected, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2367 add_call(&trace_expected, 3, &dummy_serviceid, provider, &cookie, 0, 0);
2369 init_call_trace(&trace_got);
2370 hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, provider, &cookie);
2371 ok(hr == S_OK, "got 0x%08x\n", hr);
2373 ok_trace(&trace_expected, &trace_got);
2374 free_call_trace(&trace_got);
2375 free_call_trace(&trace_expected);
2377 /* same with ::Revoke path */
2378 init_call_trace(&trace_expected);
2380 add_call(&trace_expected, 1, proff, &IID_IServiceProvider, 0, 0, 0);
2381 add_call(&trace_expected, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2382 add_call(&trace_expected, 4, (void*)(DWORD_PTR)cookie, 0, 0, 0, 0);
2384 init_call_trace(&trace_got);
2385 hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, 0, &cookie);
2386 ok(hr == S_OK, "got 0x%08x\n", hr);
2387 ok_trace(&trace_expected, &trace_got);
2388 free_call_trace(&trace_got);
2389 free_call_trace(&trace_expected);
2391 IServiceProvider_Release(provider);
2392 IProfferService_Release(proff);
2395 static void test_SHCreateWorkerWindowA(void)
2403 if (is_win2k_and_lower)
2405 win_skip("SHCreateWorkerWindowA not available\n");
2409 hwnd = pSHCreateWorkerWindowA(0, NULL, 0, 0, 0, 0);
2410 ok(hwnd != 0, "expected window\n");
2412 GetClassName(hwnd, classA, 20);
2413 ok(lstrcmpA(classA, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA);
2415 ret = GetWindowLongPtrA(hwnd, 0);
2416 ok(ret == 0, "got %ld\n", ret);
2419 memset(&cliA, 0, sizeof(cliA));
2420 res = GetClassInfoA(GetModuleHandle("shlwapi.dll"), "WorkerA", &cliA);
2421 ok(res, "failed to get class info\n");
2422 ok(cliA.style == 0, "got 0x%08x\n", cliA.style);
2423 ok(cliA.cbClsExtra == 0, "got %d\n", cliA.cbClsExtra);
2424 ok(cliA.cbWndExtra == sizeof(LONG_PTR), "got %d\n", cliA.cbWndExtra);
2425 ok(cliA.lpszMenuName == 0, "got %s\n", cliA.lpszMenuName);
2427 DestroyWindow(hwnd);
2429 /* set extra bytes */
2430 hwnd = pSHCreateWorkerWindowA(0, NULL, 0, 0, 0, 0xdeadbeef);
2431 ok(hwnd != 0, "expected window\n");
2433 GetClassName(hwnd, classA, 20);
2434 ok(lstrcmpA(classA, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA);
2436 ret = GetWindowLongPtrA(hwnd, 0);
2437 ok(ret == 0xdeadbeef, "got %ld\n", ret);
2440 ret = GetWindowLongA(hwnd, GWL_EXSTYLE);
2441 ok(ret == WS_EX_WINDOWEDGE ||
2442 ret == (WS_EX_WINDOWEDGE|WS_EX_LAYOUTRTL) /* systems with RTL locale */, "0x%08lx\n", ret);
2444 DestroyWindow(hwnd);
2446 hwnd = pSHCreateWorkerWindowA(0, NULL, WS_EX_TOOLWINDOW, 0, 0, 0);
2447 ret = GetWindowLongA(hwnd, GWL_EXSTYLE);
2448 ok(ret == (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW) ||
2449 ret == (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW|WS_EX_LAYOUTRTL) /* systems with RTL locale */, "0x%08lx\n", ret);
2450 DestroyWindow(hwnd);
2453 static HRESULT WINAPI SF_QueryInterface(IShellFolder *iface,
2454 REFIID riid, void **ppv)
2456 /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */
2457 ok(!IsEqualGUID(&IID_IShellFolder, riid),
2458 "Unexpected QI for IShellFolder\n");
2459 return E_NOINTERFACE;
2462 static ULONG WINAPI SF_AddRef(IShellFolder *iface)
2467 static ULONG WINAPI SF_Release(IShellFolder *iface)
2472 static HRESULT WINAPI SF_ParseDisplayName(IShellFolder *iface,
2473 HWND owner, LPBC reserved, LPOLESTR displayName, ULONG *eaten,
2474 LPITEMIDLIST *idl, ULONG *attr)
2476 ok(0, "Didn't expect ParseDisplayName\n");
2480 static HRESULT WINAPI SF_EnumObjects(IShellFolder *iface,
2481 HWND owner, SHCONTF flags, IEnumIDList **enm)
2483 *enm = (IEnumIDList*)0xcafebabe;
2487 static HRESULT WINAPI SF_BindToObject(IShellFolder *iface,
2488 LPCITEMIDLIST idl, LPBC reserved, REFIID riid, void **obj)
2490 ok(0, "Didn't expect BindToObject\n");
2494 static HRESULT WINAPI SF_BindToStorage(IShellFolder *iface,
2495 LPCITEMIDLIST idl, LPBC reserved, REFIID riid, void **obj)
2497 ok(0, "Didn't expect BindToStorage\n");
2501 static HRESULT WINAPI SF_CompareIDs(IShellFolder *iface,
2502 LPARAM lparam, LPCITEMIDLIST idl1, LPCITEMIDLIST idl2)
2504 ok(0, "Didn't expect CompareIDs\n");
2508 static HRESULT WINAPI SF_CreateViewObject(IShellFolder *iface,
2509 HWND owner, REFIID riid, void **out)
2511 ok(0, "Didn't expect CreateViewObject\n");
2515 static HRESULT WINAPI SF_GetAttributesOf(IShellFolder *iface,
2516 UINT cidl, LPCITEMIDLIST *idl, SFGAOF *inOut)
2518 ok(0, "Didn't expect GetAttributesOf\n");
2522 static HRESULT WINAPI SF_GetUIObjectOf(IShellFolder *iface,
2523 HWND owner, UINT cidl, LPCITEMIDLIST *idls, REFIID riid, UINT *inOut,
2526 ok(0, "Didn't expect GetUIObjectOf\n");
2530 static HRESULT WINAPI SF_GetDisplayNameOf(IShellFolder *iface,
2531 LPCITEMIDLIST idl, SHGDNF flags, STRRET *name)
2533 ok(0, "Didn't expect GetDisplayNameOf\n");
2537 static HRESULT WINAPI SF_SetNameOf(IShellFolder *iface,
2538 HWND hwnd, LPCITEMIDLIST idl, LPCOLESTR name, SHGDNF flags,
2539 LPITEMIDLIST *idlOut)
2541 ok(0, "Didn't expect SetNameOf\n");
2545 static IShellFolderVtbl ShellFolderVtbl = {
2549 SF_ParseDisplayName,
2554 SF_CreateViewObject,
2557 SF_GetDisplayNameOf,
2561 static IShellFolder ShellFolder = { &ShellFolderVtbl };
2563 static void test_SHIShellFolder_EnumObjects(void)
2567 IShellFolder *folder;
2569 if(!pSHIShellFolder_EnumObjects || is_win2k_and_lower){
2570 win_skip("SHIShellFolder_EnumObjects not available\n");
2575 /* NULL object crashes on Windows */
2576 hres = pSHIShellFolder_EnumObjects(NULL, NULL, 0, NULL);
2579 /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */
2580 enm = (IEnumIDList*)0xdeadbeef;
2581 hres = pSHIShellFolder_EnumObjects(&ShellFolder, NULL, 0, &enm);
2582 ok(hres == S_OK, "SHIShellFolder_EnumObjects failed: 0x%08x\n", hres);
2583 ok(enm == (IEnumIDList*)0xcafebabe, "Didn't get expected enumerator location, instead: %p\n", enm);
2585 /* SHIShellFolder_EnumObjects isn't strict about the IShellFolder object */
2586 hres = pSHGetDesktopFolder(&folder);
2587 ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
2590 hres = pSHIShellFolder_EnumObjects(folder, NULL, 0, &enm);
2591 ok(hres == S_OK, "SHIShellFolder_EnumObjects failed: 0x%08x\n", hres);
2592 ok(enm != NULL, "Didn't get an enumerator\n");
2594 IEnumIDList_Release(enm);
2596 IShellFolder_Release(folder);
2599 static void write_inifile(LPCWSTR filename)
2604 static const char data[] =
2607 "AnotherKey=asdf\r\n";
2609 file = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
2610 if(file == INVALID_HANDLE_VALUE)
2613 WriteFile(file, data, sizeof(data), &written, NULL);
2618 #define verify_inifile(f, e) r_verify_inifile(__LINE__, f, e)
2619 static void r_verify_inifile(unsigned l, LPCWSTR filename, LPCSTR exp)
2625 file = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
2626 if(file == INVALID_HANDLE_VALUE)
2629 ReadFile(file, buf, sizeof(buf) * sizeof(CHAR), &read, NULL);
2634 ok_(__FILE__,l)(!strcmp(buf, exp), "Expected:\n%s\nGot:\n%s\n", exp,
2638 static void test_SHGetIniString(void)
2641 WCHAR out[64] = {0};
2643 static const WCHAR TestAppW[] = {'T','e','s','t','A','p','p',0};
2644 static const WCHAR TestIniW[] = {'C',':','\\','t','e','s','t','.','i','n','i',0};
2645 static const WCHAR AKeyW[] = {'A','K','e','y',0};
2646 static const WCHAR AnotherKeyW[] = {'A','n','o','t','h','e','r','K','e','y',0};
2647 static const WCHAR JunkKeyW[] = {'J','u','n','k','K','e','y',0};
2649 if(!pSHGetIniStringW || is_win2k_and_lower){
2650 win_skip("SHGetIniStringW is not available\n");
2654 write_inifile(TestIniW);
2657 /* these crash on Windows */
2658 ret = pSHGetIniStringW(NULL, NULL, NULL, 0, NULL);
2659 ret = pSHGetIniStringW(NULL, AKeyW, out, sizeof(out), TestIniW);
2660 ret = pSHGetIniStringW(TestAppW, AKeyW, NULL, sizeof(out), TestIniW);
2663 ret = pSHGetIniStringW(TestAppW, AKeyW, out, 0, TestIniW);
2664 ok(ret == 0, "SHGetIniStringW should have given 0, instead: %d\n", ret);
2666 /* valid arguments */
2667 ret = pSHGetIniStringW(TestAppW, NULL, out, sizeof(out), TestIniW);
2668 ok(broken(ret == 0) || /* win 98 */
2669 ret == 4, "SHGetIniStringW should have given 4, instead: %d\n", ret);
2670 ok(!lstrcmpW(out, AKeyW), "Expected %s, got: %s\n",
2671 wine_dbgstr_w(AKeyW), wine_dbgstr_w(out));
2673 ret = pSHGetIniStringW(TestAppW, AKeyW, out, sizeof(out), TestIniW);
2674 ok(broken(ret == 0) || /* win 98 */
2675 ret == 1, "SHGetIniStringW should have given 1, instead: %d\n", ret);
2676 ok(broken(*out == 0) || /*win 98 */
2677 !strcmp_wa(out, "1"), "Expected L\"1\", got: %s\n", wine_dbgstr_w(out));
2679 ret = pSHGetIniStringW(TestAppW, AnotherKeyW, out, sizeof(out), TestIniW);
2680 ok(broken(ret == 0) || /* win 98 */
2681 ret == 4, "SHGetIniStringW should have given 4, instead: %d\n", ret);
2682 ok(broken(*out == 0) || /* win 98 */
2683 !strcmp_wa(out, "asdf"), "Expected L\"asdf\", got: %s\n", wine_dbgstr_w(out));
2685 ret = pSHGetIniStringW(TestAppW, JunkKeyW, out, sizeof(out), TestIniW);
2686 ok(ret == 0, "SHGetIniStringW should have given 0, instead: %d\n", ret);
2687 ok(*out == 0, "Expected L\"\", got: %s\n", wine_dbgstr_w(out));
2689 DeleteFileW(TestIniW);
2692 static void test_SHSetIniString(void)
2696 static const WCHAR TestAppW[] = {'T','e','s','t','A','p','p',0};
2697 static const WCHAR AnotherAppW[] = {'A','n','o','t','h','e','r','A','p','p',0};
2698 static const WCHAR TestIniW[] = {'C',':','\\','t','e','s','t','.','i','n','i',0};
2699 static const WCHAR AKeyW[] = {'A','K','e','y',0};
2700 static const WCHAR NewKeyW[] = {'N','e','w','K','e','y',0};
2701 static const WCHAR AValueW[] = {'A','V','a','l','u','e',0};
2703 if(!pSHSetIniStringW || is_win2k_and_lower){
2704 win_skip("SHSetIniStringW is not available\n");
2708 write_inifile(TestIniW);
2710 ret = pSHSetIniStringW(TestAppW, AKeyW, AValueW, TestIniW);
2711 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2712 todo_wine /* wine sticks an extra \r\n at the end of the file */
2713 verify_inifile(TestIniW, "[TestApp]\r\nAKey=AValue\r\nAnotherKey=asdf\r\n");
2715 ret = pSHSetIniStringW(TestAppW, AKeyW, NULL, TestIniW);
2716 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2717 verify_inifile(TestIniW, "[TestApp]\r\nAnotherKey=asdf\r\n");
2719 ret = pSHSetIniStringW(AnotherAppW, NewKeyW, AValueW, TestIniW);
2720 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2721 verify_inifile(TestIniW, "[TestApp]\r\nAnotherKey=asdf\r\n[AnotherApp]\r\nNewKey=AValue\r\n");
2723 ret = pSHSetIniStringW(TestAppW, NULL, AValueW, TestIniW);
2724 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2725 verify_inifile(TestIniW, "[AnotherApp]\r\nNewKey=AValue\r\n");
2727 DeleteFileW(TestIniW);
2730 enum _shellkey_flags {
2731 SHKEY_Root_HKCU = 0x1,
2732 SHKEY_Root_HKLM = 0x2,
2733 SHKEY_Key_Explorer = 0x00,
2734 SHKEY_Key_Shell = 0x10,
2735 SHKEY_Key_ShellNoRoam = 0x20,
2736 SHKEY_Key_Classes = 0x30,
2737 SHKEY_Subkey_Default = 0x0000,
2738 SHKEY_Subkey_ResourceName = 0x1000,
2739 SHKEY_Subkey_Handlers = 0x2000,
2740 SHKEY_Subkey_Associations = 0x3000,
2741 SHKEY_Subkey_Volatile = 0x4000,
2742 SHKEY_Subkey_MUICache = 0x5000,
2743 SHKEY_Subkey_FileExts = 0x6000
2746 static void test_SHGetShellKey(void)
2748 static const WCHAR ShellFoldersW[] = { 'S','h','e','l','l',' ','F','o','l','d','e','r','s',0 };
2749 static const WCHAR WineTestW[] = { 'W','i','n','e','T','e','s','t',0 };
2751 void *pPathBuildRootW = GetProcAddress(hShlwapi, "PathBuildRootW");
2752 DWORD *alloc_data, data, size;
2756 if (!pSHGetShellKey)
2758 win_skip("SHGetShellKey(ordinal 491) isn't available\n");
2763 if (pPathBuildRootW && pPathBuildRootW == pSHGetShellKey)
2765 win_skip("SHGetShellKey(ordinal 491) used for PathBuildRootW\n");
2769 if (is_win9x || is_win2k_and_lower)
2771 win_skip("Ordinal 491 used for another call, skipping SHGetShellKey tests\n");
2775 /* Vista+ limits SHKEY enumeration values */
2776 SetLastError(0xdeadbeef);
2777 hkey = pSHGetShellKey(SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2780 /* Tests not working on Vista+ */
2783 hkey = pSHGetShellKey(SHKEY_Root_HKLM|SHKEY_Key_Classes, NULL, FALSE);
2784 ok(hkey != NULL, "hkey = NULL\n");
2788 hkey = pSHGetShellKey(SHKEY_Root_HKCU|SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2789 ok(hkey != NULL, "hkey = NULL\n");
2792 hkey = pSHGetShellKey(SHKEY_Root_HKLM|SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2793 ok(hkey != NULL, "hkey = NULL\n");
2796 hkey = pSHGetShellKey(SHKEY_Root_HKLM, WineTestW, FALSE);
2797 ok(hkey == NULL, "hkey != NULL\n");
2799 hkey = pSHGetShellKey(SHKEY_Root_HKLM, WineTestW, TRUE);
2800 ok(hkey != NULL, "Can't create key\n");
2803 hkey = pSHGetShellKey(SHKEY_Root_HKLM, NULL, FALSE);
2804 ok(hkey != NULL, "Can't create key\n");
2805 ok(SUCCEEDED(RegDeleteKeyW(hkey, WineTestW)), "Can't delte key\n");
2808 if (!pSKGetValueW || !pSKSetValueW || !pSKDeleteValueW || !pSKAllocValueW)
2810 win_skip("SKGetValueW, SKSetValueW, SKDeleteValueW or SKAllocValueW not available\n");
2814 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
2815 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres);
2818 hres = pSKSetValueW(SHKEY_Root_HKLM, WineTestW, NULL, REG_DWORD, &data, sizeof(DWORD));
2819 ok(hres == S_OK, "hres = %x\n", hres);
2822 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, NULL, &size);
2823 ok(hres == S_OK, "hres = %x\n", hres);
2824 ok(size == sizeof(DWORD), "size = %d\n", size);
2827 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
2828 ok(hres == S_OK, "hres = %x\n", hres);
2829 ok(size == sizeof(DWORD), "size = %d\n", size);
2830 ok(data == 1234, "data = %d\n", data);
2832 hres = pSKAllocValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, (void**)&alloc_data, &size);
2833 ok(hres == S_OK, "hres= %x\n", hres);
2834 ok(size == sizeof(DWORD), "size = %d\n", size);
2835 ok(*alloc_data == 1234, "*alloc_data = %d\n", *alloc_data);
2836 LocalFree(alloc_data);
2838 hres = pSKDeleteValueW(SHKEY_Root_HKLM, WineTestW, NULL);
2839 ok(hres == S_OK, "hres = %x\n", hres);
2841 hres = pSKDeleteValueW(SHKEY_Root_HKLM, WineTestW, NULL);
2842 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres);
2844 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
2845 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres);
2847 hkey = pSHGetShellKey(SHKEY_Root_HKLM, NULL, FALSE);
2848 ok(hkey != NULL, "Can't create key\n");
2849 ok(SUCCEEDED(RegDeleteKeyW(hkey, WineTestW)), "Can't delte key\n");
2853 static void init_pointers(void)
2855 #define MAKEFUNC(f, ord) (p##f = (void*)GetProcAddress(hShlwapi, (LPSTR)(ord)))
2856 MAKEFUNC(SHAllocShared, 7);
2857 MAKEFUNC(SHLockShared, 8);
2858 MAKEFUNC(SHUnlockShared, 9);
2859 MAKEFUNC(SHFreeShared, 10);
2860 MAKEFUNC(GetAcceptLanguagesA, 14);
2861 MAKEFUNC(SHSetWindowBits, 165);
2862 MAKEFUNC(ConnectToConnectionPoint, 168);
2863 MAKEFUNC(SHSearchMapInt, 198);
2864 MAKEFUNC(SHCreateWorkerWindowA, 257);
2865 MAKEFUNC(GUIDFromStringA, 269);
2866 MAKEFUNC(SHPackDispParams, 282);
2867 MAKEFUNC(IConnectionPoint_InvokeWithCancel, 283);
2868 MAKEFUNC(IConnectionPoint_SimpleInvoke, 284);
2869 MAKEFUNC(SHGetIniStringW, 294);
2870 MAKEFUNC(SHSetIniStringW, 295);
2871 MAKEFUNC(SHFormatDateTimeA, 353);
2872 MAKEFUNC(SHFormatDateTimeW, 354);
2873 MAKEFUNC(SHIShellFolder_EnumObjects, 404);
2874 MAKEFUNC(SHGetObjectCompatFlags, 476);
2875 MAKEFUNC(IUnknown_QueryServiceExec, 484);
2876 MAKEFUNC(SHGetShellKey, 491);
2877 MAKEFUNC(SHPropertyBag_ReadLONG, 496);
2878 MAKEFUNC(IUnknown_ProfferService, 514);
2879 MAKEFUNC(SKGetValueW, 516);
2880 MAKEFUNC(SKSetValueW, 517);
2881 MAKEFUNC(SKDeleteValueW, 518);
2882 MAKEFUNC(SKAllocValueW, 519);
2888 hShlwapi = GetModuleHandleA("shlwapi.dll");
2889 is_win2k_and_lower = GetProcAddress(hShlwapi, "StrChrNW") == 0;
2890 is_win9x = GetProcAddress(hShlwapi, (LPSTR)99) == 0; /* StrCpyNXA */
2892 /* SHCreateStreamOnFileEx was introduced in shlwapi v6.0 */
2893 if(!GetProcAddress(hShlwapi, "SHCreateStreamOnFileEx")){
2894 win_skip("Too old shlwapi version\n");
2900 hmlang = LoadLibraryA("mlang.dll");
2901 pLcidToRfc1766A = (void *)GetProcAddress(hmlang, "LcidToRfc1766A");
2903 hshell32 = LoadLibraryA("shell32.dll");
2904 pSHGetDesktopFolder = (void *)GetProcAddress(hshell32, "SHGetDesktopFolder");
2906 test_GetAcceptLanguagesA();
2907 test_SHSearchMapInt();
2908 test_alloc_shared();
2910 test_GetShellSecurityDescriptor();
2911 test_SHPackDispParams();
2912 test_IConnectionPoint();
2913 test_SHPropertyBag_ReadLONG();
2914 test_SHSetWindowBits();
2915 test_SHFormatDateTimeA();
2916 test_SHFormatDateTimeW();
2917 test_SHGetObjectCompatFlags();
2918 test_IUnknown_QueryServiceExec();
2919 test_IUnknown_ProfferService();
2920 test_SHCreateWorkerWindowA();
2921 test_SHIShellFolder_EnumObjects();
2922 test_SHGetIniString();
2923 test_SHSetIniString();
2924 test_SHGetShellKey();
2926 FreeLibrary(hshell32);
2927 FreeLibrary(hmlang);