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, "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, "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, "got %d\n", ret);
1819 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1821 flags = FDTF_SHORTDATE | FDTF_LONGDATE;
1822 SetLastError(0xdeadbeef);
1823 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1824 ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
1825 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1827 flags = FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE;
1828 SetLastError(0xdeadbeef);
1829 buff[0] = 0; /* NT4 doesn't clear the buffer on failure */
1830 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1831 ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
1832 ok(GetLastError() == 0xdeadbeef ||
1833 broken(GetLastError() == ERROR_INVALID_FLAGS), /* Win9x/WinMe/NT4 */
1834 "expected 0xdeadbeef, got %d\n", GetLastError());
1836 /* now check returned strings */
1837 flags = FDTF_SHORTTIME;
1838 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1839 ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
1840 SetLastError(0xdeadbeef);
1841 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1842 if (ret == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1844 win_skip("Needed W-functions are not implemented\n");
1847 ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
1848 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1850 flags = FDTF_LONGTIME;
1851 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1852 ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
1853 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1854 ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
1855 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1857 /* both time flags */
1858 flags = FDTF_LONGTIME | FDTF_SHORTTIME;
1859 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1860 ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
1861 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1862 ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
1863 ok(lstrcmpW(buff, buff2) == 0, "expected equal string\n");
1865 flags = FDTF_SHORTDATE;
1866 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1867 ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
1868 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1869 ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
1870 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1872 flags = FDTF_LONGDATE;
1873 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1874 ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
1875 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1876 ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
1877 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1879 /* both date flags */
1880 flags = FDTF_LONGDATE | FDTF_SHORTDATE;
1881 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1882 ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
1883 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1884 ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
1885 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1887 /* various combinations of date/time flags */
1888 flags = FDTF_LONGDATE | FDTF_SHORTTIME;
1889 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1890 ok(ret == lstrlenW(buff)+1, "got %d, length %d\n", ret, lstrlenW(buff)+1);
1891 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1892 ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
1893 lstrcatW(buff2, commaW);
1894 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1895 ok(ret == lstrlenW(buff3)+1, "got %d\n", ret);
1896 lstrcatW(buff2, buff3);
1897 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1899 flags = FDTF_LONGDATE | FDTF_LONGTIME;
1900 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1901 ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
1902 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1903 ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
1904 lstrcatW(buff2, commaW);
1905 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1906 ok(ret == lstrlenW(buff3)+1, "got %d\n", ret);
1907 lstrcatW(buff2, buff3);
1908 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1910 flags = FDTF_SHORTDATE | FDTF_SHORTTIME;
1911 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1912 ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
1913 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1914 ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
1915 lstrcatW(buff2, spaceW);
1916 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1917 ok(ret == lstrlenW(buff3)+1, "got %d\n", ret);
1918 lstrcatW(buff2, buff3);
1919 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1921 flags = FDTF_SHORTDATE | FDTF_LONGTIME;
1922 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1923 ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
1924 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1925 ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
1926 lstrcatW(buff2, spaceW);
1927 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1928 ok(ret == lstrlenW(buff3)+1, "got %d\n", ret);
1929 lstrcatW(buff2, buff3);
1930 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1933 static void test_SHGetObjectCompatFlags(void)
1935 struct compat_value {
1940 struct compat_value values[] = {
1941 { "OTNEEDSSFCACHE", 0x1 },
1942 { "NO_WEBVIEW", 0x2 },
1943 { "UNBINDABLE", 0x4 },
1945 { "NEEDSFILESYSANCESTOR", 0x10 },
1946 { "NOTAFILESYSTEM", 0x20 },
1947 { "CTXMENU_NOVERBS", 0x40 },
1948 { "CTXMENU_LIMITEDQI", 0x80 },
1949 { "COCREATESHELLFOLDERONLY", 0x100 },
1950 { "NEEDSSTORAGEANCESTOR", 0x200 },
1951 { "NOLEGACYWEBVIEW", 0x400 },
1952 { "CTXMENU_XPQCMFLAGS", 0x1000 },
1953 { "NOIPROPERTYSTORE", 0x2000 }
1956 static const char compat_path[] = "Software\\Microsoft\\Windows\\CurrentVersion\\ShellCompatibility\\Objects";
1957 void *pColorAdjustLuma = GetProcAddress(hShlwapi, "ColorAdjustLuma");
1958 CHAR keyA[39]; /* {CLSID} */
1963 if (!pSHGetObjectCompatFlags)
1965 win_skip("SHGetObjectCompatFlags isn't available\n");
1969 if (pColorAdjustLuma && pColorAdjustLuma == pSHGetObjectCompatFlags) /* win2k */
1971 win_skip("Skipping SHGetObjectCompatFlags, same ordinal used for ColorAdjustLuma\n");
1976 ret = pSHGetObjectCompatFlags(NULL, NULL);
1977 ok(ret == 0, "got %d\n", ret);
1979 ret = RegOpenKeyA(HKEY_LOCAL_MACHINE, compat_path, &root);
1980 if (ret != ERROR_SUCCESS)
1982 skip("No compatibility class data found\n");
1986 for (i = 0; RegEnumKeyA(root, i, keyA, sizeof(keyA)) == ERROR_SUCCESS; i++)
1990 if (RegOpenKeyA(root, keyA, &clsid_key) == ERROR_SUCCESS)
1993 DWORD expected = 0, got, length = sizeof(valueA);
1997 for (v = 0; RegEnumValueA(clsid_key, v, valueA, &length, NULL, NULL, NULL, NULL) == ERROR_SUCCESS; v++)
2001 for (j = 0; j < sizeof(values)/sizeof(struct compat_value); j++)
2002 if (lstrcmpA(values[j].nameA, valueA) == 0)
2004 expected |= values[j].value;
2008 length = sizeof(valueA);
2011 pGUIDFromStringA(keyA, &clsid);
2012 got = pSHGetObjectCompatFlags(NULL, &clsid);
2013 ok(got == expected, "got 0x%08x, expected 0x%08x. Key %s\n", got, expected, keyA);
2015 RegCloseKey(clsid_key);
2023 const IOleCommandTargetVtbl *lpVtbl;
2025 } IOleCommandTargetImpl;
2027 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl;
2029 static IOleCommandTarget* IOleCommandTargetImpl_Construct(void)
2031 IOleCommandTargetImpl *obj;
2033 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2034 obj->lpVtbl = &IOleCommandTargetImpl_Vtbl;
2037 return (IOleCommandTarget*)obj;
2040 static HRESULT WINAPI IOleCommandTargetImpl_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppvObj)
2042 IOleCommandTargetImpl *This = (IOleCommandTargetImpl *)iface;
2044 if (IsEqualIID(riid, &IID_IUnknown) ||
2045 IsEqualIID(riid, &IID_IOleCommandTarget))
2052 IUnknown_AddRef(iface);
2056 return E_NOINTERFACE;
2059 static ULONG WINAPI IOleCommandTargetImpl_AddRef(IOleCommandTarget *iface)
2061 IOleCommandTargetImpl *This = (IOleCommandTargetImpl *)iface;
2062 return InterlockedIncrement(&This->ref);
2065 static ULONG WINAPI IOleCommandTargetImpl_Release(IOleCommandTarget *iface)
2067 IOleCommandTargetImpl *This = (IOleCommandTargetImpl *)iface;
2068 ULONG ref = InterlockedDecrement(&This->ref);
2072 HeapFree(GetProcessHeap(), 0, This);
2078 static HRESULT WINAPI IOleCommandTargetImpl_QueryStatus(
2079 IOleCommandTarget *iface, const GUID *group, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText)
2084 static HRESULT WINAPI IOleCommandTargetImpl_Exec(
2085 IOleCommandTarget *iface,
2086 const GUID *CmdGroup,
2092 add_call(&trace_got, 3, CmdGroup, (void*)(DWORD_PTR)nCmdID, (void*)(DWORD_PTR)nCmdexecopt, pvaIn, pvaOut);
2096 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl =
2098 IOleCommandTargetImpl_QueryInterface,
2099 IOleCommandTargetImpl_AddRef,
2100 IOleCommandTargetImpl_Release,
2101 IOleCommandTargetImpl_QueryStatus,
2102 IOleCommandTargetImpl_Exec
2106 const IServiceProviderVtbl *lpVtbl;
2108 } IServiceProviderImpl;
2111 const IProfferServiceVtbl *lpVtbl;
2113 } IProfferServiceImpl;
2116 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl;
2117 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl;
2119 static IServiceProvider* IServiceProviderImpl_Construct(void)
2121 IServiceProviderImpl *obj;
2123 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2124 obj->lpVtbl = &IServiceProviderImpl_Vtbl;
2127 return (IServiceProvider*)obj;
2130 static IProfferService* IProfferServiceImpl_Construct(void)
2132 IProfferServiceImpl *obj;
2134 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2135 obj->lpVtbl = &IProfferServiceImpl_Vtbl;
2138 return (IProfferService*)obj;
2141 static HRESULT WINAPI IServiceProviderImpl_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppvObj)
2143 IServiceProviderImpl *This = (IServiceProviderImpl *)iface;
2145 if (IsEqualIID(riid, &IID_IUnknown) ||
2146 IsEqualIID(riid, &IID_IServiceProvider))
2153 IUnknown_AddRef(iface);
2154 /* native uses redefined IID_IServiceProvider symbol, so we can't compare pointers */
2155 if (IsEqualIID(riid, &IID_IServiceProvider))
2156 add_call(&trace_got, 1, iface, &IID_IServiceProvider, 0, 0, 0);
2160 return E_NOINTERFACE;
2163 static ULONG WINAPI IServiceProviderImpl_AddRef(IServiceProvider *iface)
2165 IServiceProviderImpl *This = (IServiceProviderImpl *)iface;
2166 return InterlockedIncrement(&This->ref);
2169 static ULONG WINAPI IServiceProviderImpl_Release(IServiceProvider *iface)
2171 IServiceProviderImpl *This = (IServiceProviderImpl *)iface;
2172 ULONG ref = InterlockedDecrement(&This->ref);
2176 HeapFree(GetProcessHeap(), 0, This);
2182 static HRESULT WINAPI IServiceProviderImpl_QueryService(
2183 IServiceProvider *iface, REFGUID service, REFIID riid, void **ppv)
2185 /* native uses redefined pointer for IID_IOleCommandTarget, not one from uuid.lib */
2186 if (IsEqualIID(riid, &IID_IOleCommandTarget))
2188 add_call(&trace_got, 2, iface, service, &IID_IOleCommandTarget, 0, 0);
2189 *ppv = IOleCommandTargetImpl_Construct();
2191 if (IsEqualIID(riid, &IID_IProfferService))
2193 if (IsEqualIID(service, &IID_IProfferService))
2194 add_call(&trace_got, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2195 *ppv = IProfferServiceImpl_Construct();
2200 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl =
2202 IServiceProviderImpl_QueryInterface,
2203 IServiceProviderImpl_AddRef,
2204 IServiceProviderImpl_Release,
2205 IServiceProviderImpl_QueryService
2208 static void test_IUnknown_QueryServiceExec(void)
2210 IServiceProvider *provider = IServiceProviderImpl_Construct();
2211 static const GUID dummy_serviceid = { 0xdeadbeef };
2212 static const GUID dummy_groupid = { 0xbeefbeef };
2213 call_trace_t trace_expected;
2216 /* on <=W2K platforms same ordinal used for another export with different
2217 prototype, so skipping using this indirect condition */
2218 if (is_win2k_and_lower)
2220 win_skip("IUnknown_QueryServiceExec is not available\n");
2224 /* null source pointer */
2225 hr = pIUnknown_QueryServiceExec(NULL, &dummy_serviceid, &dummy_groupid, 0, 0, 0, 0);
2226 ok(hr == E_FAIL, "got 0x%08x\n", hr);
2229 IUnknown_QueryServiceExec( ptr1, serviceid, groupid, arg1, arg2, arg3, arg4);
2230 -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &prov );
2231 -> IServiceProvider_QueryService( prov, serviceid, &IID_IOleCommandTarget, &obj );
2232 -> IOleCommandTarget_Exec( obj, groupid, arg1, arg2, arg3, arg4 );
2234 init_call_trace(&trace_expected);
2236 add_call(&trace_expected, 1, provider, &IID_IServiceProvider, 0, 0, 0);
2237 add_call(&trace_expected, 2, provider, &dummy_serviceid, &IID_IOleCommandTarget, 0, 0);
2238 add_call(&trace_expected, 3, &dummy_groupid, (void*)0x1, (void*)0x2, (void*)0x3, (void*)0x4);
2240 init_call_trace(&trace_got);
2241 hr = pIUnknown_QueryServiceExec((IUnknown*)provider, &dummy_serviceid, &dummy_groupid, 0x1, 0x2, (void*)0x3, (void*)0x4);
2242 ok(hr == S_OK, "got 0x%08x\n", hr);
2244 ok_trace(&trace_expected, &trace_got);
2246 free_call_trace(&trace_expected);
2247 free_call_trace(&trace_got);
2249 IServiceProvider_Release(provider);
2253 static HRESULT WINAPI IProfferServiceImpl_QueryInterface(IProfferService *iface, REFIID riid, void **ppvObj)
2255 IProfferServiceImpl *This = (IProfferServiceImpl *)iface;
2257 if (IsEqualIID(riid, &IID_IUnknown) ||
2258 IsEqualIID(riid, &IID_IProfferService))
2262 else if (IsEqualIID(riid, &IID_IServiceProvider))
2264 *ppvObj = IServiceProviderImpl_Construct();
2265 add_call(&trace_got, 1, iface, &IID_IServiceProvider, 0, 0, 0);
2271 IUnknown_AddRef(iface);
2275 return E_NOINTERFACE;
2278 static ULONG WINAPI IProfferServiceImpl_AddRef(IProfferService *iface)
2280 IProfferServiceImpl *This = (IProfferServiceImpl *)iface;
2281 return InterlockedIncrement(&This->ref);
2284 static ULONG WINAPI IProfferServiceImpl_Release(IProfferService *iface)
2286 IProfferServiceImpl *This = (IProfferServiceImpl *)iface;
2287 ULONG ref = InterlockedDecrement(&This->ref);
2291 HeapFree(GetProcessHeap(), 0, This);
2297 static HRESULT WINAPI IProfferServiceImpl_ProfferService(IProfferService *iface,
2298 REFGUID service, IServiceProvider *pService, DWORD *pCookie)
2300 add_call(&trace_got, 3, service, pService, pCookie, 0, 0);
2304 static HRESULT WINAPI IProfferServiceImpl_RevokeService(IProfferService *iface, DWORD cookie)
2306 add_call(&trace_got, 4, (void*)(DWORD_PTR)cookie, 0, 0, 0, 0);
2310 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl =
2312 IProfferServiceImpl_QueryInterface,
2313 IProfferServiceImpl_AddRef,
2314 IProfferServiceImpl_Release,
2315 IProfferServiceImpl_ProfferService,
2316 IProfferServiceImpl_RevokeService
2319 static void test_IUnknown_ProfferService(void)
2321 IServiceProvider *provider = IServiceProviderImpl_Construct();
2322 IProfferService *proff = IProfferServiceImpl_Construct();
2323 static const GUID dummy_serviceid = { 0xdeadbeef };
2324 call_trace_t trace_expected;
2328 /* on <=W2K platforms same ordinal used for another export with different
2329 prototype, so skipping using this indirect condition */
2330 if (is_win2k_and_lower)
2332 win_skip("IUnknown_ProfferService is not available\n");
2336 /* null source pointer */
2337 hr = pIUnknown_ProfferService(NULL, &dummy_serviceid, 0, 0);
2338 ok(hr == E_FAIL, "got 0x%08x\n", hr);
2341 IUnknown_ProfferService( ptr1, serviceid, arg1, arg2);
2342 -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &provider );
2343 -> IServiceProvider_QueryService( provider, &IID_IProfferService, &IID_IProfferService, &proffer );
2345 if (service pointer not null):
2346 -> IProfferService_ProfferService( proffer, serviceid, arg1, arg2 );
2348 -> IProfferService_RevokeService( proffer, *arg2 );
2350 init_call_trace(&trace_expected);
2352 add_call(&trace_expected, 1, proff, &IID_IServiceProvider, 0, 0, 0);
2353 add_call(&trace_expected, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2354 add_call(&trace_expected, 3, &dummy_serviceid, provider, &cookie, 0, 0);
2356 init_call_trace(&trace_got);
2357 hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, provider, &cookie);
2358 ok(hr == S_OK, "got 0x%08x\n", hr);
2360 ok_trace(&trace_expected, &trace_got);
2361 free_call_trace(&trace_got);
2362 free_call_trace(&trace_expected);
2364 /* same with ::Revoke path */
2365 init_call_trace(&trace_expected);
2367 add_call(&trace_expected, 1, proff, &IID_IServiceProvider, 0, 0, 0);
2368 add_call(&trace_expected, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2369 add_call(&trace_expected, 4, (void*)(DWORD_PTR)cookie, 0, 0, 0, 0);
2371 init_call_trace(&trace_got);
2372 hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, 0, &cookie);
2373 ok(hr == S_OK, "got 0x%08x\n", hr);
2374 ok_trace(&trace_expected, &trace_got);
2375 free_call_trace(&trace_got);
2376 free_call_trace(&trace_expected);
2378 IServiceProvider_Release(provider);
2379 IProfferService_Release(proff);
2382 static void test_SHCreateWorkerWindowA(void)
2390 if (is_win2k_and_lower)
2392 win_skip("SHCreateWorkerWindowA not available\n");
2396 hwnd = pSHCreateWorkerWindowA(0, NULL, 0, 0, 0, 0);
2397 ok(hwnd != 0, "expected window\n");
2399 GetClassName(hwnd, classA, 20);
2400 ok(lstrcmpA(classA, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA);
2402 ret = GetWindowLongPtrA(hwnd, 0);
2403 ok(ret == 0, "got %ld\n", ret);
2406 memset(&cliA, 0, sizeof(cliA));
2407 res = GetClassInfoA(GetModuleHandle("shlwapi.dll"), "WorkerA", &cliA);
2408 ok(res, "failed to get class info\n");
2409 ok(cliA.style == 0, "got 0x%08x\n", cliA.style);
2410 ok(cliA.cbClsExtra == 0, "got %d\n", cliA.cbClsExtra);
2411 ok(cliA.cbWndExtra == sizeof(LONG_PTR), "got %d\n", cliA.cbWndExtra);
2412 ok(cliA.lpszMenuName == 0, "got %s\n", cliA.lpszMenuName);
2414 DestroyWindow(hwnd);
2416 /* set extra bytes */
2417 hwnd = pSHCreateWorkerWindowA(0, NULL, 0, 0, 0, 0xdeadbeef);
2418 ok(hwnd != 0, "expected window\n");
2420 GetClassName(hwnd, classA, 20);
2421 ok(lstrcmpA(classA, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA);
2423 ret = GetWindowLongPtrA(hwnd, 0);
2424 ok(ret == 0xdeadbeef, "got %ld\n", ret);
2427 ret = GetWindowLongA(hwnd, GWL_EXSTYLE);
2428 ok(ret == WS_EX_WINDOWEDGE ||
2429 ret == (WS_EX_WINDOWEDGE|WS_EX_LAYOUTRTL) /* systems with RTL locale */, "0x%08lx\n", ret);
2431 DestroyWindow(hwnd);
2433 hwnd = pSHCreateWorkerWindowA(0, NULL, WS_EX_TOOLWINDOW, 0, 0, 0);
2434 ret = GetWindowLongA(hwnd, GWL_EXSTYLE);
2435 ok(ret == (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW) ||
2436 ret == (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW|WS_EX_LAYOUTRTL) /* systems with RTL locale */, "0x%08lx\n", ret);
2437 DestroyWindow(hwnd);
2440 static HRESULT WINAPI SF_QueryInterface(IShellFolder *iface,
2441 REFIID riid, void **ppv)
2443 /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */
2444 ok(!IsEqualGUID(&IID_IShellFolder, riid),
2445 "Unexpected QI for IShellFolder\n");
2446 return E_NOINTERFACE;
2449 static ULONG WINAPI SF_AddRef(IShellFolder *iface)
2454 static ULONG WINAPI SF_Release(IShellFolder *iface)
2459 static HRESULT WINAPI SF_ParseDisplayName(IShellFolder *iface,
2460 HWND owner, LPBC reserved, LPOLESTR displayName, ULONG *eaten,
2461 LPITEMIDLIST *idl, ULONG *attr)
2463 ok(0, "Didn't expect ParseDisplayName\n");
2467 static HRESULT WINAPI SF_EnumObjects(IShellFolder *iface,
2468 HWND owner, SHCONTF flags, IEnumIDList **enm)
2470 *enm = (IEnumIDList*)0xcafebabe;
2474 static HRESULT WINAPI SF_BindToObject(IShellFolder *iface,
2475 LPCITEMIDLIST idl, LPBC reserved, REFIID riid, void **obj)
2477 ok(0, "Didn't expect BindToObject\n");
2481 static HRESULT WINAPI SF_BindToStorage(IShellFolder *iface,
2482 LPCITEMIDLIST idl, LPBC reserved, REFIID riid, void **obj)
2484 ok(0, "Didn't expect BindToStorage\n");
2488 static HRESULT WINAPI SF_CompareIDs(IShellFolder *iface,
2489 LPARAM lparam, LPCITEMIDLIST idl1, LPCITEMIDLIST idl2)
2491 ok(0, "Didn't expect CompareIDs\n");
2495 static HRESULT WINAPI SF_CreateViewObject(IShellFolder *iface,
2496 HWND owner, REFIID riid, void **out)
2498 ok(0, "Didn't expect CreateViewObject\n");
2502 static HRESULT WINAPI SF_GetAttributesOf(IShellFolder *iface,
2503 UINT cidl, LPCITEMIDLIST *idl, SFGAOF *inOut)
2505 ok(0, "Didn't expect GetAttributesOf\n");
2509 static HRESULT WINAPI SF_GetUIObjectOf(IShellFolder *iface,
2510 HWND owner, UINT cidl, LPCITEMIDLIST *idls, REFIID riid, UINT *inOut,
2513 ok(0, "Didn't expect GetUIObjectOf\n");
2517 static HRESULT WINAPI SF_GetDisplayNameOf(IShellFolder *iface,
2518 LPCITEMIDLIST idl, SHGDNF flags, STRRET *name)
2520 ok(0, "Didn't expect GetDisplayNameOf\n");
2524 static HRESULT WINAPI SF_SetNameOf(IShellFolder *iface,
2525 HWND hwnd, LPCITEMIDLIST idl, LPCOLESTR name, SHGDNF flags,
2526 LPITEMIDLIST *idlOut)
2528 ok(0, "Didn't expect SetNameOf\n");
2532 static IShellFolderVtbl ShellFolderVtbl = {
2536 SF_ParseDisplayName,
2541 SF_CreateViewObject,
2544 SF_GetDisplayNameOf,
2548 static IShellFolder ShellFolder = { &ShellFolderVtbl };
2550 static void test_SHIShellFolder_EnumObjects(void)
2554 IShellFolder *folder;
2556 if(!pSHIShellFolder_EnumObjects || is_win2k_and_lower){
2557 win_skip("SHIShellFolder_EnumObjects not available\n");
2562 /* NULL object crashes on Windows */
2563 hres = pSHIShellFolder_EnumObjects(NULL, NULL, 0, NULL);
2566 /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */
2567 enm = (IEnumIDList*)0xdeadbeef;
2568 hres = pSHIShellFolder_EnumObjects(&ShellFolder, NULL, 0, &enm);
2569 ok(hres == S_OK, "SHIShellFolder_EnumObjects failed: 0x%08x\n", hres);
2570 ok(enm == (IEnumIDList*)0xcafebabe, "Didn't get expected enumerator location, instead: %p\n", enm);
2572 /* SHIShellFolder_EnumObjects isn't strict about the IShellFolder object */
2573 hres = pSHGetDesktopFolder(&folder);
2574 ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
2577 hres = pSHIShellFolder_EnumObjects(folder, NULL, 0, &enm);
2578 ok(hres == S_OK, "SHIShellFolder_EnumObjects failed: 0x%08x\n", hres);
2579 ok(enm != NULL, "Didn't get an enumerator\n");
2581 IEnumIDList_Release(enm);
2583 IShellFolder_Release(folder);
2586 static void write_inifile(LPCWSTR filename)
2591 static const char data[] =
2594 "AnotherKey=asdf\r\n";
2596 file = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
2597 if(file == INVALID_HANDLE_VALUE)
2600 WriteFile(file, data, sizeof(data), &written, NULL);
2605 #define verify_inifile(f, e) r_verify_inifile(__LINE__, f, e)
2606 static void r_verify_inifile(unsigned l, LPCWSTR filename, LPCSTR exp)
2612 file = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
2613 if(file == INVALID_HANDLE_VALUE)
2616 ReadFile(file, buf, sizeof(buf) * sizeof(CHAR), &read, NULL);
2621 ok_(__FILE__,l)(!strcmp(buf, exp), "Expected:\n%s\nGot:\n%s\n", exp,
2625 static void test_SHGetIniString(void)
2628 WCHAR out[64] = {0};
2630 static const WCHAR TestAppW[] = {'T','e','s','t','A','p','p',0};
2631 static const WCHAR TestIniW[] = {'C',':','\\','t','e','s','t','.','i','n','i',0};
2632 static const WCHAR AKeyW[] = {'A','K','e','y',0};
2633 static const WCHAR AnotherKeyW[] = {'A','n','o','t','h','e','r','K','e','y',0};
2634 static const WCHAR JunkKeyW[] = {'J','u','n','k','K','e','y',0};
2636 if(!pSHGetIniStringW || is_win2k_and_lower){
2637 win_skip("SHGetIniStringW is not available\n");
2641 write_inifile(TestIniW);
2644 /* these crash on Windows */
2645 ret = pSHGetIniStringW(NULL, NULL, NULL, 0, NULL);
2646 ret = pSHGetIniStringW(NULL, AKeyW, out, sizeof(out), TestIniW);
2647 ret = pSHGetIniStringW(TestAppW, AKeyW, NULL, sizeof(out), TestIniW);
2650 ret = pSHGetIniStringW(TestAppW, AKeyW, out, 0, TestIniW);
2651 ok(ret == 0, "SHGetIniStringW should have given 0, instead: %d\n", ret);
2653 /* valid arguments */
2654 ret = pSHGetIniStringW(TestAppW, NULL, out, sizeof(out), TestIniW);
2655 ok(broken(ret == 0) || /* win 98 */
2656 ret == 4, "SHGetIniStringW should have given 4, instead: %d\n", ret);
2657 ok(!lstrcmpW(out, AKeyW), "Expected %s, got: %s\n",
2658 wine_dbgstr_w(AKeyW), wine_dbgstr_w(out));
2660 ret = pSHGetIniStringW(TestAppW, AKeyW, out, sizeof(out), TestIniW);
2661 ok(broken(ret == 0) || /* win 98 */
2662 ret == 1, "SHGetIniStringW should have given 1, instead: %d\n", ret);
2663 ok(broken(*out == 0) || /*win 98 */
2664 !strcmp_wa(out, "1"), "Expected L\"1\", got: %s\n", wine_dbgstr_w(out));
2666 ret = pSHGetIniStringW(TestAppW, AnotherKeyW, out, sizeof(out), TestIniW);
2667 ok(broken(ret == 0) || /* win 98 */
2668 ret == 4, "SHGetIniStringW should have given 4, instead: %d\n", ret);
2669 ok(broken(*out == 0) || /* win 98 */
2670 !strcmp_wa(out, "asdf"), "Expected L\"asdf\", got: %s\n", wine_dbgstr_w(out));
2672 ret = pSHGetIniStringW(TestAppW, JunkKeyW, out, sizeof(out), TestIniW);
2673 ok(ret == 0, "SHGetIniStringW should have given 0, instead: %d\n", ret);
2674 ok(*out == 0, "Expected L\"\", got: %s\n", wine_dbgstr_w(out));
2676 DeleteFileW(TestIniW);
2679 static void test_SHSetIniString(void)
2683 static const WCHAR TestAppW[] = {'T','e','s','t','A','p','p',0};
2684 static const WCHAR AnotherAppW[] = {'A','n','o','t','h','e','r','A','p','p',0};
2685 static const WCHAR TestIniW[] = {'C',':','\\','t','e','s','t','.','i','n','i',0};
2686 static const WCHAR AKeyW[] = {'A','K','e','y',0};
2687 static const WCHAR NewKeyW[] = {'N','e','w','K','e','y',0};
2688 static const WCHAR AValueW[] = {'A','V','a','l','u','e',0};
2690 if(!pSHSetIniStringW || is_win2k_and_lower){
2691 win_skip("SHSetIniStringW is not available\n");
2695 write_inifile(TestIniW);
2697 ret = pSHSetIniStringW(TestAppW, AKeyW, AValueW, TestIniW);
2698 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2699 todo_wine /* wine sticks an extra \r\n at the end of the file */
2700 verify_inifile(TestIniW, "[TestApp]\r\nAKey=AValue\r\nAnotherKey=asdf\r\n");
2702 ret = pSHSetIniStringW(TestAppW, AKeyW, NULL, TestIniW);
2703 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2704 verify_inifile(TestIniW, "[TestApp]\r\nAnotherKey=asdf\r\n");
2706 ret = pSHSetIniStringW(AnotherAppW, NewKeyW, AValueW, TestIniW);
2707 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2708 verify_inifile(TestIniW, "[TestApp]\r\nAnotherKey=asdf\r\n[AnotherApp]\r\nNewKey=AValue\r\n");
2710 ret = pSHSetIniStringW(TestAppW, NULL, AValueW, TestIniW);
2711 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2712 verify_inifile(TestIniW, "[AnotherApp]\r\nNewKey=AValue\r\n");
2714 DeleteFileW(TestIniW);
2717 enum _shellkey_flags {
2718 SHKEY_Root_HKCU = 0x1,
2719 SHKEY_Root_HKLM = 0x2,
2720 SHKEY_Key_Explorer = 0x00,
2721 SHKEY_Key_Shell = 0x10,
2722 SHKEY_Key_ShellNoRoam = 0x20,
2723 SHKEY_Key_Classes = 0x30,
2724 SHKEY_Subkey_Default = 0x0000,
2725 SHKEY_Subkey_ResourceName = 0x1000,
2726 SHKEY_Subkey_Handlers = 0x2000,
2727 SHKEY_Subkey_Associations = 0x3000,
2728 SHKEY_Subkey_Volatile = 0x4000,
2729 SHKEY_Subkey_MUICache = 0x5000,
2730 SHKEY_Subkey_FileExts = 0x6000
2733 static void test_SHGetShellKey(void)
2735 static const WCHAR ShellFoldersW[] = { 'S','h','e','l','l',' ','F','o','l','d','e','r','s',0 };
2736 static const WCHAR WineTestW[] = { 'W','i','n','e','T','e','s','t',0 };
2738 void *pPathBuildRootW = GetProcAddress(hShlwapi, "PathBuildRootW");
2739 DWORD *alloc_data, data, size;
2743 if (!pSHGetShellKey)
2745 win_skip("SHGetShellKey(ordinal 491) isn't available\n");
2750 if (pPathBuildRootW && pPathBuildRootW == pSHGetShellKey)
2752 win_skip("SHGetShellKey(ordinal 491) used for PathBuildRootW\n");
2756 if (is_win9x || is_win2k_and_lower)
2758 win_skip("Ordinal 491 used for another call, skipping SHGetShellKey tests\n");
2762 /* Vista+ limits SHKEY enumeration values */
2763 SetLastError(0xdeadbeef);
2764 hkey = pSHGetShellKey(SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2767 /* Tests not working on Vista+ */
2770 hkey = pSHGetShellKey(SHKEY_Root_HKLM|SHKEY_Key_Classes, NULL, FALSE);
2771 ok(hkey != NULL, "hkey = NULL\n");
2775 hkey = pSHGetShellKey(SHKEY_Root_HKCU|SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2776 ok(hkey != NULL, "hkey = NULL\n");
2779 hkey = pSHGetShellKey(SHKEY_Root_HKLM|SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2780 ok(hkey != NULL, "hkey = NULL\n");
2783 hkey = pSHGetShellKey(SHKEY_Root_HKLM, WineTestW, FALSE);
2784 ok(hkey == NULL, "hkey != NULL\n");
2786 hkey = pSHGetShellKey(SHKEY_Root_HKLM, WineTestW, TRUE);
2787 ok(hkey != NULL, "Can't create key\n");
2790 hkey = pSHGetShellKey(SHKEY_Root_HKLM, NULL, FALSE);
2791 ok(hkey != NULL, "Can't create key\n");
2792 ok(SUCCEEDED(RegDeleteKeyW(hkey, WineTestW)), "Can't delte key\n");
2795 if (!pSKGetValueW || !pSKSetValueW || !pSKDeleteValueW || !pSKAllocValueW)
2797 win_skip("SKGetValueW, SKSetValueW, SKDeleteValueW or SKAllocValueW not available\n");
2801 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
2802 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres);
2805 hres = pSKSetValueW(SHKEY_Root_HKLM, WineTestW, NULL, REG_DWORD, &data, sizeof(DWORD));
2806 ok(hres == S_OK, "hres = %x\n", hres);
2809 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, NULL, &size);
2810 ok(hres == S_OK, "hres = %x\n", hres);
2811 ok(size == sizeof(DWORD), "size = %d\n", size);
2814 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
2815 ok(hres == S_OK, "hres = %x\n", hres);
2816 ok(size == sizeof(DWORD), "size = %d\n", size);
2817 ok(data == 1234, "data = %d\n", data);
2819 hres = pSKAllocValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, (void**)&alloc_data, &size);
2820 ok(hres == S_OK, "hres= %x\n", hres);
2821 ok(size == sizeof(DWORD), "size = %d\n", size);
2822 ok(*alloc_data == 1234, "*alloc_data = %d\n", *alloc_data);
2823 LocalFree(alloc_data);
2825 hres = pSKDeleteValueW(SHKEY_Root_HKLM, WineTestW, NULL);
2826 ok(hres == S_OK, "hres = %x\n", hres);
2828 hres = pSKDeleteValueW(SHKEY_Root_HKLM, WineTestW, NULL);
2829 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres);
2831 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
2832 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres);
2834 hkey = pSHGetShellKey(SHKEY_Root_HKLM, NULL, FALSE);
2835 ok(hkey != NULL, "Can't create key\n");
2836 ok(SUCCEEDED(RegDeleteKeyW(hkey, WineTestW)), "Can't delte key\n");
2840 static void init_pointers(void)
2842 #define MAKEFUNC(f, ord) (p##f = (void*)GetProcAddress(hShlwapi, (LPSTR)(ord)))
2843 MAKEFUNC(SHAllocShared, 7);
2844 MAKEFUNC(SHLockShared, 8);
2845 MAKEFUNC(SHUnlockShared, 9);
2846 MAKEFUNC(SHFreeShared, 10);
2847 MAKEFUNC(GetAcceptLanguagesA, 14);
2848 MAKEFUNC(SHSetWindowBits, 165);
2849 MAKEFUNC(ConnectToConnectionPoint, 168);
2850 MAKEFUNC(SHSearchMapInt, 198);
2851 MAKEFUNC(SHCreateWorkerWindowA, 257);
2852 MAKEFUNC(GUIDFromStringA, 269);
2853 MAKEFUNC(SHPackDispParams, 282);
2854 MAKEFUNC(IConnectionPoint_InvokeWithCancel, 283);
2855 MAKEFUNC(IConnectionPoint_SimpleInvoke, 284);
2856 MAKEFUNC(SHGetIniStringW, 294);
2857 MAKEFUNC(SHSetIniStringW, 295);
2858 MAKEFUNC(SHFormatDateTimeA, 353);
2859 MAKEFUNC(SHFormatDateTimeW, 354);
2860 MAKEFUNC(SHIShellFolder_EnumObjects, 404);
2861 MAKEFUNC(SHGetObjectCompatFlags, 476);
2862 MAKEFUNC(IUnknown_QueryServiceExec, 484);
2863 MAKEFUNC(SHGetShellKey, 491);
2864 MAKEFUNC(SHPropertyBag_ReadLONG, 496);
2865 MAKEFUNC(IUnknown_ProfferService, 514);
2866 MAKEFUNC(SKGetValueW, 516);
2867 MAKEFUNC(SKSetValueW, 517);
2868 MAKEFUNC(SKDeleteValueW, 518);
2869 MAKEFUNC(SKAllocValueW, 519);
2875 hShlwapi = GetModuleHandleA("shlwapi.dll");
2876 is_win2k_and_lower = GetProcAddress(hShlwapi, "StrChrNW") == 0;
2877 is_win9x = GetProcAddress(hShlwapi, (LPSTR)99) == 0; /* StrCpyNXA */
2879 /* SHCreateStreamOnFileEx was introduced in shlwapi v6.0 */
2880 if(!GetProcAddress(hShlwapi, "SHCreateStreamOnFileEx")){
2881 win_skip("Too old shlwapi version\n");
2887 hmlang = LoadLibraryA("mlang.dll");
2888 pLcidToRfc1766A = (void *)GetProcAddress(hmlang, "LcidToRfc1766A");
2890 hshell32 = LoadLibraryA("shell32.dll");
2891 pSHGetDesktopFolder = (void *)GetProcAddress(hshell32, "SHGetDesktopFolder");
2893 test_GetAcceptLanguagesA();
2894 test_SHSearchMapInt();
2895 test_alloc_shared();
2897 test_GetShellSecurityDescriptor();
2898 test_SHPackDispParams();
2899 test_IConnectionPoint();
2900 test_SHPropertyBag_ReadLONG();
2901 test_SHSetWindowBits();
2902 test_SHFormatDateTimeA();
2903 test_SHFormatDateTimeW();
2904 test_SHGetObjectCompatFlags();
2905 test_IUnknown_QueryServiceExec();
2906 test_IUnknown_ProfferService();
2907 test_SHCreateWorkerWindowA();
2908 test_SHIShellFolder_EnumObjects();
2909 test_SHGetIniString();
2910 test_SHSetIniString();
2911 test_SHGetShellKey();
2913 FreeLibrary(hshell32);
2914 FreeLibrary(hmlang);