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, ret;
642 SECURITY_DESCRIPTOR_CONTROL control;
644 ok(IsValidSecurityDescriptor(psd), "returned value is not valid SD\n");
646 ret = GetSecurityDescriptorControl(psd, &control, &dwRev);
647 ok(ret, "GetSecurityDescriptorControl failed with error %u\n", GetLastError());
648 ok(0 == (control & SE_SELF_RELATIVE), "SD should be absolute\n");
650 ret = GetSecurityDescriptorDacl(psd, &bHasDacl, &pAcl, &bDefaulted);
651 ok(ret, "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 ret = GetAclInformation(pAcl, &asiSize, sizeof(asiSize), AclSizeInformation);
666 ok(ret, "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 ret = GetAce(pAcl, 0, (LPVOID*)&paaa);
674 ok(ret, "GetAce failed with error %u\n", GetLastError());
675 ok(paaa->Header.AceType == ACCESS_ALLOWED_ACE_TYPE,
676 "Invalid ACE type %d\n", paaa->Header.AceType);
677 ok(paaa->Header.AceFlags == 0, "Invalid ACE flags %x\n", paaa->Header.AceFlags);
678 ok(paaa->Mask == GENERIC_ALL, "Invalid ACE mask %x\n", paaa->Mask);
680 ret = GetAce(pAcl, 1, (LPVOID*)&paaa);
681 ok(ret, "GetAce failed with error %u\n", GetLastError());
682 ok(paaa->Header.AceType == ACCESS_DENIED_ACE_TYPE,
683 "Invalid ACE type %d\n", paaa->Header.AceType);
684 /* first one of two ACEs generated from inheritable entry - without inheritance */
685 ok(paaa->Header.AceFlags == 0, "Invalid ACE flags %x\n", paaa->Header.AceFlags);
686 ok(paaa->Mask == GENERIC_WRITE, "Invalid ACE mask %x\n", paaa->Mask);
688 ret = GetAce(pAcl, 2, (LPVOID*)&paaa);
689 ok(ret, "GetAce failed with error %u\n", GetLastError());
690 ok(paaa->Header.AceType == ACCESS_DENIED_ACE_TYPE,
691 "Invalid ACE type %d\n", paaa->Header.AceType);
692 /* second ACE - with inheritance */
693 ok(paaa->Header.AceFlags == MY_INHERITANCE,
694 "Invalid ACE flags %x\n", paaa->Header.AceFlags);
695 ok(paaa->Mask == GENERIC_READ, "Invalid ACE mask %x\n", paaa->Mask);
704 static void test_SHPackDispParams(void)
710 if(!pSHPackDispParams)
711 win_skip("SHPackSidpParams not available\n");
713 memset(¶ms, 0xc0, sizeof(params));
714 memset(vars, 0xc0, sizeof(vars));
715 hres = pSHPackDispParams(¶ms, vars, 1, VT_I4, 0xdeadbeef);
716 ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres);
717 ok(params.cArgs == 1, "params.cArgs = %d\n", params.cArgs);
718 ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
719 ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
720 ok(params.rgvarg == vars, "params.rgvarg = %p\n", params.rgvarg);
721 ok(V_VT(vars) == VT_I4, "V_VT(var) = %d\n", V_VT(vars));
722 ok(V_I4(vars) == 0xdeadbeef, "failed %x\n", V_I4(vars));
724 memset(¶ms, 0xc0, sizeof(params));
725 hres = pSHPackDispParams(¶ms, NULL, 0, 0);
726 ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres);
727 ok(params.cArgs == 0, "params.cArgs = %d\n", params.cArgs);
728 ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
729 ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
730 ok(params.rgvarg == NULL, "params.rgvarg = %p\n", params.rgvarg);
732 memset(vars, 0xc0, sizeof(vars));
733 memset(¶ms, 0xc0, sizeof(params));
734 hres = pSHPackDispParams(¶ms, vars, 4, VT_BSTR, (void*)0xdeadbeef, VT_EMPTY, 10,
735 VT_I4, 100, VT_DISPATCH, (void*)0xdeadbeef);
736 ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres);
737 ok(params.cArgs == 4, "params.cArgs = %d\n", params.cArgs);
738 ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
739 ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
740 ok(params.rgvarg == vars, "params.rgvarg = %p\n", params.rgvarg);
741 ok(V_VT(vars) == VT_DISPATCH, "V_VT(vars[0]) = %x\n", V_VT(vars));
742 ok(V_I4(vars) == 0xdeadbeef, "V_I4(vars[0]) = %x\n", V_I4(vars));
743 ok(V_VT(vars+1) == VT_I4, "V_VT(vars[1]) = %d\n", V_VT(vars+1));
744 ok(V_I4(vars+1) == 100, "V_I4(vars[1]) = %x\n", V_I4(vars+1));
745 ok(V_VT(vars+2) == VT_I4, "V_VT(vars[2]) = %d\n", V_VT(vars+2));
746 ok(V_I4(vars+2) == 10, "V_I4(vars[2]) = %x\n", V_I4(vars+2));
747 ok(V_VT(vars+3) == VT_BSTR, "V_VT(vars[3]) = %d\n", V_VT(vars+3));
748 ok(V_BSTR(vars+3) == (void*)0xdeadbeef, "V_BSTR(vars[3]) = %p\n", V_BSTR(vars+3));
753 IDispatch IDispatch_iface;
757 static inline Disp *impl_from_IDispatch(IDispatch *iface)
759 return CONTAINING_RECORD(iface, Disp, IDispatch_iface);
762 typedef struct _contain
764 IConnectionPointContainer IConnectionPointContainer_iface;
768 IConnectionPoint **pt;
771 static inline Contain *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
773 return CONTAINING_RECORD(iface, Contain, IConnectionPointContainer_iface);
776 typedef struct _cntptn
778 IConnectionPoint IConnectionPoint_iface;
787 static inline ConPt *impl_from_IConnectionPoint(IConnectionPoint *iface)
789 return CONTAINING_RECORD(iface, ConPt, IConnectionPoint_iface);
794 IEnumConnections IEnumConnections_iface;
801 static inline EnumCon *impl_from_IEnumConnections(IEnumConnections *iface)
803 return CONTAINING_RECORD(iface, EnumCon, IEnumConnections_iface);
806 typedef struct _enumpt
808 IEnumConnectionPoints IEnumConnectionPoints_iface;
815 static inline EnumPt *impl_from_IEnumConnectionPoints(IEnumConnectionPoints *iface)
817 return CONTAINING_RECORD(iface, EnumPt, IEnumConnectionPoints_iface);
821 static HRESULT WINAPI Disp_QueryInterface(
828 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDispatch))
835 IUnknown_AddRef(This);
839 trace("no interface\n");
840 return E_NOINTERFACE;
843 static ULONG WINAPI Disp_AddRef(IDispatch* This)
845 Disp *iface = impl_from_IDispatch(This);
846 return InterlockedIncrement(&iface->refCount);
849 static ULONG WINAPI Disp_Release(IDispatch* This)
851 Disp *iface = impl_from_IDispatch(This);
854 ret = InterlockedDecrement(&iface->refCount);
856 HeapFree(GetProcessHeap(),0,This);
860 static HRESULT WINAPI Disp_GetTypeInfoCount(
864 return ERROR_SUCCESS;
867 static HRESULT WINAPI Disp_GetTypeInfo(
873 return ERROR_SUCCESS;
876 static HRESULT WINAPI Disp_GetIDsOfNames(
884 return ERROR_SUCCESS;
887 static HRESULT WINAPI Disp_Invoke(
893 DISPPARAMS *pDispParams,
895 EXCEPINFO *pExcepInfo,
898 trace("%p %x %p %x %x %p %p %p %p\n",This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
900 ok(dispIdMember == 0xa0 || dispIdMember == 0xa1, "Unknown dispIdMember\n");
901 ok(pDispParams != NULL, "Invoked with NULL pDispParams\n");
902 ok(wFlags == DISPATCH_METHOD, "Wrong flags %x\n",wFlags);
903 ok(lcid == 0,"Wrong lcid %x\n",lcid);
904 if (dispIdMember == 0xa0)
906 ok(pDispParams->cArgs == 0, "params.cArgs = %d\n", pDispParams->cArgs);
907 ok(pDispParams->cNamedArgs == 0, "params.cNamedArgs = %d\n", pDispParams->cArgs);
908 ok(pDispParams->rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", pDispParams->rgdispidNamedArgs);
909 ok(pDispParams->rgvarg == NULL, "params.rgvarg = %p\n", pDispParams->rgvarg);
911 else if (dispIdMember == 0xa1)
913 ok(pDispParams->cArgs == 2, "params.cArgs = %d\n", pDispParams->cArgs);
914 ok(pDispParams->cNamedArgs == 0, "params.cNamedArgs = %d\n", pDispParams->cArgs);
915 ok(pDispParams->rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", pDispParams->rgdispidNamedArgs);
916 ok(V_VT(pDispParams->rgvarg) == VT_BSTR, "V_VT(var) = %d\n", V_VT(pDispParams->rgvarg));
917 ok(V_I4(pDispParams->rgvarg) == 0xdeadcafe , "failed %p\n", V_BSTR(pDispParams->rgvarg));
918 ok(V_VT(pDispParams->rgvarg+1) == VT_I4, "V_VT(var) = %d\n", V_VT(pDispParams->rgvarg+1));
919 ok(V_I4(pDispParams->rgvarg+1) == 0xdeadbeef, "failed %x\n", V_I4(pDispParams->rgvarg+1));
922 return ERROR_SUCCESS;
925 static const IDispatchVtbl disp_vtbl = {
930 Disp_GetTypeInfoCount,
936 static HRESULT WINAPI Enum_QueryInterface(
937 IEnumConnections* This,
943 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumConnections))
950 IUnknown_AddRef(This);
954 trace("no interface\n");
955 return E_NOINTERFACE;
958 static ULONG WINAPI Enum_AddRef(IEnumConnections* This)
960 EnumCon *iface = impl_from_IEnumConnections(This);
961 return InterlockedIncrement(&iface->refCount);
964 static ULONG WINAPI Enum_Release(IEnumConnections* This)
966 EnumCon *iface = impl_from_IEnumConnections(This);
969 ret = InterlockedDecrement(&iface->refCount);
971 HeapFree(GetProcessHeap(),0,This);
975 static HRESULT WINAPI Enum_Next(
976 IEnumConnections* This,
981 EnumCon *iface = impl_from_IEnumConnections(This);
983 if (cConnections > 0 && iface->idx < iface->pt->sinkCount)
985 rgcd->pUnk = iface->pt->sink[iface->idx];
986 IUnknown_AddRef(iface->pt->sink[iface->idx]);
997 static HRESULT WINAPI Enum_Skip(
998 IEnumConnections* This,
1004 static HRESULT WINAPI Enum_Reset(
1005 IEnumConnections* This)
1010 static HRESULT WINAPI Enum_Clone(
1011 IEnumConnections* This,
1012 IEnumConnections **ppEnum)
1017 static const IEnumConnectionsVtbl enum_vtbl = {
1019 Enum_QueryInterface,
1028 static HRESULT WINAPI ConPt_QueryInterface(
1029 IConnectionPoint* This,
1035 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IConnectionPoint))
1042 IUnknown_AddRef(This);
1046 trace("no interface\n");
1047 return E_NOINTERFACE;
1050 static ULONG WINAPI ConPt_AddRef(
1051 IConnectionPoint* This)
1053 ConPt *iface = impl_from_IConnectionPoint(This);
1054 return InterlockedIncrement(&iface->refCount);
1057 static ULONG WINAPI ConPt_Release(
1058 IConnectionPoint* This)
1060 ConPt *iface = impl_from_IConnectionPoint(This);
1063 ret = InterlockedDecrement(&iface->refCount);
1066 if (iface->sinkCount > 0)
1069 for (i = 0; i < iface->sinkCount; i++)
1072 IUnknown_Release(iface->sink[i]);
1074 HeapFree(GetProcessHeap(),0,iface->sink);
1076 HeapFree(GetProcessHeap(),0,This);
1081 static HRESULT WINAPI ConPt_GetConnectionInterface(
1082 IConnectionPoint* This,
1086 ConPt *iface = impl_from_IConnectionPoint(This);
1093 memcpy(pIID,&iface->id,sizeof(GUID));
1097 static HRESULT WINAPI ConPt_GetConnectionPointContainer(
1098 IConnectionPoint* This,
1099 IConnectionPointContainer **ppCPC)
1101 ConPt *iface = impl_from_IConnectionPoint(This);
1103 *ppCPC = &iface->container->IConnectionPointContainer_iface;
1107 static HRESULT WINAPI ConPt_Advise(
1108 IConnectionPoint* This,
1112 ConPt *iface = impl_from_IConnectionPoint(This);
1114 if (iface->sinkCount == 0)
1115 iface->sink = HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown*));
1117 iface->sink = HeapReAlloc(GetProcessHeap(),0,iface->sink,sizeof(IUnknown*)*(iface->sinkCount+1));
1118 iface->sink[iface->sinkCount] = pUnkSink;
1119 IUnknown_AddRef(pUnkSink);
1121 *pdwCookie = iface->sinkCount;
1125 static HRESULT WINAPI ConPt_Unadvise(
1126 IConnectionPoint* This,
1129 ConPt *iface = impl_from_IConnectionPoint(This);
1131 if (dwCookie > iface->sinkCount)
1135 IUnknown_Release(iface->sink[dwCookie-1]);
1136 iface->sink[dwCookie-1] = NULL;
1141 static HRESULT WINAPI ConPt_EnumConnections(
1142 IConnectionPoint* This,
1143 IEnumConnections **ppEnum)
1147 ec = HeapAlloc(GetProcessHeap(),0,sizeof(EnumCon));
1148 ec->IEnumConnections_iface.lpVtbl = &enum_vtbl;
1150 ec->pt = impl_from_IConnectionPoint(This);
1152 *ppEnum = &ec->IEnumConnections_iface;
1157 static const IConnectionPointVtbl point_vtbl = {
1158 ConPt_QueryInterface,
1162 ConPt_GetConnectionInterface,
1163 ConPt_GetConnectionPointContainer,
1166 ConPt_EnumConnections
1169 static HRESULT WINAPI EnumPt_QueryInterface(
1170 IEnumConnectionPoints* This,
1176 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumConnectionPoints))
1183 IUnknown_AddRef(This);
1187 trace("no interface\n");
1188 return E_NOINTERFACE;
1191 static ULONG WINAPI EnumPt_AddRef(IEnumConnectionPoints* This)
1193 EnumPt *iface = impl_from_IEnumConnectionPoints(This);
1194 return InterlockedIncrement(&iface->refCount);
1197 static ULONG WINAPI EnumPt_Release(IEnumConnectionPoints* This)
1199 EnumPt *iface = impl_from_IEnumConnectionPoints(This);
1202 ret = InterlockedDecrement(&iface->refCount);
1204 HeapFree(GetProcessHeap(),0,This);
1208 static HRESULT WINAPI EnumPt_Next(
1209 IEnumConnectionPoints* This,
1211 IConnectionPoint **rgcd,
1214 EnumPt *iface = impl_from_IEnumConnectionPoints(This);
1216 if (cConnections > 0 && iface->idx < iface->container->ptCount)
1218 *rgcd = iface->container->pt[iface->idx];
1219 IUnknown_AddRef(iface->container->pt[iface->idx]);
1229 static HRESULT WINAPI EnumPt_Skip(
1230 IEnumConnectionPoints* This,
1236 static HRESULT WINAPI EnumPt_Reset(
1237 IEnumConnectionPoints* This)
1242 static HRESULT WINAPI EnumPt_Clone(
1243 IEnumConnectionPoints* This,
1244 IEnumConnectionPoints **ppEnumPt)
1249 static const IEnumConnectionPointsVtbl enumpt_vtbl = {
1251 EnumPt_QueryInterface,
1260 static HRESULT WINAPI Contain_QueryInterface(
1261 IConnectionPointContainer* This,
1267 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IConnectionPointContainer))
1274 IUnknown_AddRef(This);
1278 trace("no interface\n");
1279 return E_NOINTERFACE;
1282 static ULONG WINAPI Contain_AddRef(
1283 IConnectionPointContainer* This)
1285 Contain *iface = impl_from_IConnectionPointContainer(This);
1286 return InterlockedIncrement(&iface->refCount);
1289 static ULONG WINAPI Contain_Release(
1290 IConnectionPointContainer* This)
1292 Contain *iface = impl_from_IConnectionPointContainer(This);
1295 ret = InterlockedDecrement(&iface->refCount);
1298 if (iface->ptCount > 0)
1301 for (i = 0; i < iface->ptCount; i++)
1302 IUnknown_Release(iface->pt[i]);
1303 HeapFree(GetProcessHeap(),0,iface->pt);
1305 HeapFree(GetProcessHeap(),0,This);
1310 static HRESULT WINAPI Contain_EnumConnectionPoints(
1311 IConnectionPointContainer* This,
1312 IEnumConnectionPoints **ppEnum)
1316 ec = HeapAlloc(GetProcessHeap(),0,sizeof(EnumPt));
1317 ec->IEnumConnectionPoints_iface.lpVtbl = &enumpt_vtbl;
1320 ec->container = impl_from_IConnectionPointContainer(This);
1321 *ppEnum = &ec->IEnumConnectionPoints_iface;
1326 static HRESULT WINAPI Contain_FindConnectionPoint(
1327 IConnectionPointContainer* This,
1329 IConnectionPoint **ppCP)
1331 Contain *iface = impl_from_IConnectionPointContainer(This);
1334 if (!IsEqualIID(riid, &IID_NULL) || iface->ptCount ==0)
1336 pt = HeapAlloc(GetProcessHeap(),0,sizeof(ConPt));
1337 pt->IConnectionPoint_iface.lpVtbl = &point_vtbl;
1341 pt->container = iface;
1342 pt->id = IID_IDispatch;
1344 if (iface->ptCount == 0)
1345 iface->pt =HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown*));
1347 iface->pt = HeapReAlloc(GetProcessHeap(),0,iface->pt,sizeof(IUnknown*)*(iface->ptCount+1));
1348 iface->pt[iface->ptCount] = &pt->IConnectionPoint_iface;
1351 *ppCP = &pt->IConnectionPoint_iface;
1355 *ppCP = iface->pt[0];
1356 IUnknown_AddRef((IUnknown*)*ppCP);
1362 static const IConnectionPointContainerVtbl contain_vtbl = {
1363 Contain_QueryInterface,
1367 Contain_EnumConnectionPoints,
1368 Contain_FindConnectionPoint
1371 static void test_IConnectionPoint(void)
1375 IConnectionPoint *point;
1378 DWORD cookie = 0xffffffff;
1382 if (!pIConnectionPoint_SimpleInvoke || !pConnectToConnectionPoint)
1384 win_skip("IConnectionPoint Apis not present\n");
1388 container = HeapAlloc(GetProcessHeap(),0,sizeof(Contain));
1389 container->IConnectionPointContainer_iface.lpVtbl = &contain_vtbl;
1390 container->refCount = 1;
1391 container->ptCount = 0;
1392 container->pt = NULL;
1394 dispatch = HeapAlloc(GetProcessHeap(),0,sizeof(Disp));
1395 dispatch->IDispatch_iface.lpVtbl = &disp_vtbl;
1396 dispatch->refCount = 1;
1398 rc = pConnectToConnectionPoint((IUnknown*)dispatch, &IID_NULL, TRUE, (IUnknown*)container, &cookie, &point);
1399 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1400 ok(point != NULL, "returned ConnectionPoint is NULL\n");
1401 ok(cookie != 0xffffffff, "invalid cookie returned\n");
1403 rc = pIConnectionPoint_SimpleInvoke(point,0xa0,NULL);
1404 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1406 if (pSHPackDispParams)
1408 memset(¶ms, 0xc0, sizeof(params));
1409 memset(vars, 0xc0, sizeof(vars));
1410 rc = pSHPackDispParams(¶ms, vars, 2, VT_I4, 0xdeadbeef, VT_BSTR, 0xdeadcafe);
1411 ok(rc == S_OK, "SHPackDispParams failed: %08x\n", rc);
1413 rc = pIConnectionPoint_SimpleInvoke(point,0xa1,¶ms);
1414 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1417 win_skip("pSHPackDispParams not present\n");
1419 rc = pConnectToConnectionPoint(NULL, &IID_NULL, FALSE, (IUnknown*)container, &cookie, NULL);
1420 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1422 /* MSDN says this should be required but it crashs on XP
1423 IUnknown_Release(point);
1425 ref = IUnknown_Release((IUnknown*)container);
1426 ok(ref == 0, "leftover IConnectionPointContainer reference %i\n",ref);
1427 ref = IUnknown_Release((IUnknown*)dispatch);
1428 ok(ref == 0, "leftover IDispatch reference %i\n",ref);
1431 typedef struct _propbag
1433 IPropertyBag IPropertyBag_iface;
1438 static inline PropBag *impl_from_IPropertyBag(IPropertyBag *iface)
1440 return CONTAINING_RECORD(iface, PropBag, IPropertyBag_iface);
1444 static HRESULT WINAPI Prop_QueryInterface(
1451 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPropertyBag))
1458 IUnknown_AddRef(This);
1462 trace("no interface\n");
1463 return E_NOINTERFACE;
1466 static ULONG WINAPI Prop_AddRef(
1469 PropBag *iface = impl_from_IPropertyBag(This);
1470 return InterlockedIncrement(&iface->refCount);
1473 static ULONG WINAPI Prop_Release(
1476 PropBag *iface = impl_from_IPropertyBag(This);
1479 ret = InterlockedDecrement(&iface->refCount);
1481 HeapFree(GetProcessHeap(),0,This);
1485 static HRESULT WINAPI Prop_Read(
1487 LPCOLESTR pszPropName,
1489 IErrorLog *pErrorLog)
1491 V_VT(pVar) = VT_BLOB|VT_BYREF;
1492 V_BYREF(pVar) = (LPVOID)0xdeadcafe;
1496 static HRESULT WINAPI Prop_Write(
1498 LPCOLESTR pszPropName,
1505 static const IPropertyBagVtbl prop_vtbl = {
1506 Prop_QueryInterface,
1514 static void test_SHPropertyBag_ReadLONG(void)
1519 static const WCHAR szName1[] = {'n','a','m','e','1',0};
1521 if (!pSHPropertyBag_ReadLONG)
1523 win_skip("SHPropertyBag_ReadLONG not present\n");
1527 pb = HeapAlloc(GetProcessHeap(),0,sizeof(PropBag));
1529 pb->IPropertyBag_iface.lpVtbl = &prop_vtbl;
1532 rc = pSHPropertyBag_ReadLONG(NULL, szName1, &out);
1533 ok(rc == E_INVALIDARG || broken(rc == 0), "incorrect return %x\n",rc);
1534 ok(out == 0xfeedface, "value should not have changed\n");
1535 rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, NULL, &out);
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, NULL);
1539 ok(rc == E_INVALIDARG || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
1540 ok(out == 0xfeedface, "value should not have changed\n");
1541 rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, szName1, &out);
1542 ok(rc == DISP_E_BADVARTYPE || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
1543 ok(out == 0xfeedface || broken(out == 0xfeedfa00), "value should not have changed %x\n",out);
1544 IUnknown_Release((IUnknown*)pb);
1549 static void test_SHSetWindowBits(void)
1552 DWORD style, styleold;
1555 if(!pSHSetWindowBits)
1557 win_skip("SHSetWindowBits is not available\n");
1562 clsA.lpfnWndProc = DefWindowProcA;
1563 clsA.cbClsExtra = 0;
1564 clsA.cbWndExtra = 0;
1565 clsA.hInstance = GetModuleHandleA(NULL);
1567 clsA.hCursor = LoadCursorA(0, IDC_ARROW);
1568 clsA.hbrBackground = NULL;
1569 clsA.lpszMenuName = NULL;
1570 clsA.lpszClassName = "Shlwapi test class";
1571 RegisterClassA(&clsA);
1573 hwnd = CreateWindowA("Shlwapi test class", "Test", WS_VISIBLE, 0, 0, 100, 100,
1574 NULL, NULL, GetModuleHandle(NULL), 0);
1575 ok(IsWindow(hwnd), "failed to create window\n");
1578 SetLastError(0xdeadbeef);
1579 style = pSHSetWindowBits(NULL, GWL_STYLE, 0, 0);
1580 ok(style == 0, "expected 0 retval, got %d\n", style);
1581 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
1582 broken(GetLastError() == 0xdeadbeef), /* Win9x/WinMe */
1583 "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
1585 /* zero mask, zero flags */
1586 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1587 style = pSHSetWindowBits(hwnd, GWL_STYLE, 0, 0);
1588 ok(styleold == style, "expected old style\n");
1589 ok(styleold == GetWindowLongA(hwnd, GWL_STYLE), "expected to keep old style\n");
1592 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1593 ok(styleold & WS_VISIBLE, "expected WS_VISIBLE\n");
1594 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1596 ok(style == styleold, "expected previous style, got %x\n", style);
1597 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1599 /* test mask, unset style bit used */
1600 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1601 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1602 ok(style == styleold, "expected previous style, got %x\n", style);
1603 ok(styleold == GetWindowLongA(hwnd, GWL_STYLE), "expected to keep old style\n");
1605 /* set back with flags */
1606 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1607 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, WS_VISIBLE);
1608 ok(style == styleold, "expected previous style, got %x\n", style);
1609 ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "expected updated style\n");
1611 /* reset and try to set without a mask */
1612 pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1613 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1614 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1615 style = pSHSetWindowBits(hwnd, GWL_STYLE, 0, WS_VISIBLE);
1616 ok(style == styleold, "expected previous style, got %x\n", style);
1617 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1619 DestroyWindow(hwnd);
1621 UnregisterClassA("Shlwapi test class", GetModuleHandleA(NULL));
1624 static void test_SHFormatDateTimeA(void)
1626 FILETIME UNALIGNED filetime;
1627 CHAR buff[100], buff2[100], buff3[100];
1632 if(!pSHFormatDateTimeA)
1634 win_skip("pSHFormatDateTimeA isn't available\n");
1640 /* crashes on native */
1641 ret = pSHFormatDateTimeA(NULL, NULL, NULL, 0);
1645 SystemTimeToFileTime(&st, &filetime);
1646 /* SHFormatDateTime expects input as utc */
1647 LocalFileTimeToFileTime(&filetime, &filetime);
1649 /* no way to get required buffer length here */
1650 SetLastError(0xdeadbeef);
1651 ret = pSHFormatDateTimeA(&filetime, NULL, NULL, 0);
1652 ok(ret == 0, "got %d\n", ret);
1653 ok(GetLastError() == 0xdeadbeef || broken(GetLastError() == ERROR_SUCCESS /* Win7 */),
1654 "expected 0xdeadbeef, got %d\n", GetLastError());
1656 SetLastError(0xdeadbeef);
1657 buff[0] = 'a'; buff[1] = 0;
1658 ret = pSHFormatDateTimeA(&filetime, NULL, buff, 0);
1659 ok(ret == 0, "got %d\n", ret);
1660 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1661 ok(buff[0] == 'a', "expected same string, got %s\n", buff);
1663 /* flags needs to have FDTF_NOAUTOREADINGORDER for these tests to succeed on Vista+ */
1665 /* all combinations documented as invalid succeeded */
1666 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTTIME | FDTF_LONGTIME;
1667 SetLastError(0xdeadbeef);
1668 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1669 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1670 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1672 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_LONGDATE;
1673 SetLastError(0xdeadbeef);
1674 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1675 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1676 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1678 flags = FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE;
1679 SetLastError(0xdeadbeef);
1680 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1681 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1682 ok(GetLastError() == 0xdeadbeef ||
1683 broken(GetLastError() == ERROR_INVALID_FLAGS), /* Win9x/WinMe */
1684 "expected 0xdeadbeef, got %d\n", GetLastError());
1686 /* now check returned strings */
1687 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTTIME;
1688 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1689 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1690 ret = GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff2, sizeof(buff2));
1691 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1692 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1694 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGTIME;
1695 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1696 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1697 ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2));
1698 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1699 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1701 /* both time flags */
1702 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGTIME | FDTF_SHORTTIME;
1703 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1704 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1705 ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2));
1706 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1707 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1709 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE;
1710 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1711 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1712 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1713 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1714 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1716 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE;
1717 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1718 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1719 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1720 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1721 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1723 /* both date flags */
1724 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_SHORTDATE;
1725 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1726 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1727 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1728 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1729 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1731 /* various combinations of date/time flags */
1732 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_SHORTTIME;
1733 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1734 ok(ret == lstrlenA(buff)+1, "got %d, length %d\n", ret, lstrlenA(buff)+1);
1735 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1736 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1737 strcat(buff2, ", ");
1738 ret = GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3));
1739 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1740 strcat(buff2, buff3);
1741 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1743 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_LONGTIME;
1744 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1745 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1746 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1747 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1748 strcat(buff2, ", ");
1749 ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3));
1750 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1751 strcat(buff2, buff3);
1752 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1754 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_SHORTTIME;
1755 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1756 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1757 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1758 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1760 ret = GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3));
1761 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1762 strcat(buff2, buff3);
1763 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1765 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_LONGTIME;
1766 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1767 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1768 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1769 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1771 ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3));
1772 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1773 strcat(buff2, buff3);
1774 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1777 static void test_SHFormatDateTimeW(void)
1779 FILETIME UNALIGNED filetime;
1780 WCHAR buff[100], buff2[100], buff3[100];
1784 static const WCHAR spaceW[] = {' ',0};
1785 static const WCHAR commaW[] = {',',' ',0};
1787 if(!pSHFormatDateTimeW)
1789 win_skip("pSHFormatDateTimeW isn't available\n");
1795 /* crashes on native */
1796 ret = pSHFormatDateTimeW(NULL, NULL, NULL, 0);
1800 SystemTimeToFileTime(&st, &filetime);
1801 /* SHFormatDateTime expects input as utc */
1802 LocalFileTimeToFileTime(&filetime, &filetime);
1804 /* no way to get required buffer length here */
1805 SetLastError(0xdeadbeef);
1806 ret = pSHFormatDateTimeW(&filetime, NULL, NULL, 0);
1807 ok(ret == 0, "expected 0, got %d\n", ret);
1808 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1810 SetLastError(0xdeadbeef);
1811 buff[0] = 'a'; buff[1] = 0;
1812 ret = pSHFormatDateTimeW(&filetime, NULL, buff, 0);
1813 ok(ret == 0, "expected 0, got %d\n", ret);
1814 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1815 ok(buff[0] == 'a', "expected same string\n");
1817 /* all combinations documented as invalid succeeded */
1818 flags = FDTF_SHORTTIME | FDTF_LONGTIME;
1819 SetLastError(0xdeadbeef);
1820 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1821 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1822 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1823 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1825 flags = FDTF_SHORTDATE | FDTF_LONGDATE;
1826 SetLastError(0xdeadbeef);
1827 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1828 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1829 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1830 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1832 flags = FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE;
1833 SetLastError(0xdeadbeef);
1834 buff[0] = 0; /* NT4 doesn't clear the buffer on failure */
1835 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1836 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1837 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1838 ok(GetLastError() == 0xdeadbeef ||
1839 broken(GetLastError() == ERROR_INVALID_FLAGS), /* Win9x/WinMe/NT4 */
1840 "expected 0xdeadbeef, got %d\n", GetLastError());
1842 /* now check returned strings */
1843 flags = FDTF_SHORTTIME;
1844 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1845 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1846 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1847 SetLastError(0xdeadbeef);
1848 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1849 if (ret == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1851 win_skip("Needed W-functions are not implemented\n");
1854 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1855 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1857 flags = FDTF_LONGTIME;
1858 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1859 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1860 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1861 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1862 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1863 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1865 /* both time flags */
1866 flags = FDTF_LONGTIME | FDTF_SHORTTIME;
1867 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1868 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1869 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1870 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1871 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1872 ok(lstrcmpW(buff, buff2) == 0, "expected equal string\n");
1874 flags = FDTF_SHORTDATE;
1875 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1876 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1877 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1878 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1879 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1880 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1882 flags = FDTF_LONGDATE;
1883 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1884 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1885 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1886 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1887 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1888 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1890 /* both date flags */
1891 flags = FDTF_LONGDATE | FDTF_SHORTDATE;
1892 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1893 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1894 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1895 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1896 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1897 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1899 /* various combinations of date/time flags */
1900 flags = FDTF_LONGDATE | FDTF_SHORTTIME;
1901 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1902 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1903 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1904 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1905 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1906 lstrcatW(buff2, commaW);
1907 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1908 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1909 lstrcatW(buff2, buff3);
1910 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1912 flags = FDTF_LONGDATE | FDTF_LONGTIME;
1913 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1914 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1915 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1916 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1917 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1918 lstrcatW(buff2, commaW);
1919 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1920 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1921 lstrcatW(buff2, buff3);
1922 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1924 flags = FDTF_SHORTDATE | FDTF_SHORTTIME;
1925 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1926 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1927 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1928 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1929 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1930 lstrcatW(buff2, spaceW);
1931 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1932 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1933 lstrcatW(buff2, buff3);
1934 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1936 flags = FDTF_SHORTDATE | FDTF_LONGTIME;
1937 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1938 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1939 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1940 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1941 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1942 lstrcatW(buff2, spaceW);
1943 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1944 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1945 lstrcatW(buff2, buff3);
1946 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1949 static void test_SHGetObjectCompatFlags(void)
1951 struct compat_value {
1956 struct compat_value values[] = {
1957 { "OTNEEDSSFCACHE", 0x1 },
1958 { "NO_WEBVIEW", 0x2 },
1959 { "UNBINDABLE", 0x4 },
1961 { "NEEDSFILESYSANCESTOR", 0x10 },
1962 { "NOTAFILESYSTEM", 0x20 },
1963 { "CTXMENU_NOVERBS", 0x40 },
1964 { "CTXMENU_LIMITEDQI", 0x80 },
1965 { "COCREATESHELLFOLDERONLY", 0x100 },
1966 { "NEEDSSTORAGEANCESTOR", 0x200 },
1967 { "NOLEGACYWEBVIEW", 0x400 },
1968 { "CTXMENU_XPQCMFLAGS", 0x1000 },
1969 { "NOIPROPERTYSTORE", 0x2000 }
1972 static const char compat_path[] = "Software\\Microsoft\\Windows\\CurrentVersion\\ShellCompatibility\\Objects";
1973 void *pColorAdjustLuma = GetProcAddress(hShlwapi, "ColorAdjustLuma");
1974 CHAR keyA[39]; /* {CLSID} */
1979 if (!pSHGetObjectCompatFlags)
1981 win_skip("SHGetObjectCompatFlags isn't available\n");
1985 if (pColorAdjustLuma && pColorAdjustLuma == pSHGetObjectCompatFlags) /* win2k */
1987 win_skip("Skipping SHGetObjectCompatFlags, same ordinal used for ColorAdjustLuma\n");
1992 ret = pSHGetObjectCompatFlags(NULL, NULL);
1993 ok(ret == 0, "got %d\n", ret);
1995 ret = RegOpenKeyA(HKEY_LOCAL_MACHINE, compat_path, &root);
1996 if (ret != ERROR_SUCCESS)
1998 skip("No compatibility class data found\n");
2002 for (i = 0; RegEnumKeyA(root, i, keyA, sizeof(keyA)) == ERROR_SUCCESS; i++)
2006 if (RegOpenKeyA(root, keyA, &clsid_key) == ERROR_SUCCESS)
2009 DWORD expected = 0, got, length = sizeof(valueA);
2013 for (v = 0; RegEnumValueA(clsid_key, v, valueA, &length, NULL, NULL, NULL, NULL) == ERROR_SUCCESS; v++)
2017 for (j = 0; j < sizeof(values)/sizeof(struct compat_value); j++)
2018 if (lstrcmpA(values[j].nameA, valueA) == 0)
2020 expected |= values[j].value;
2024 length = sizeof(valueA);
2027 pGUIDFromStringA(keyA, &clsid);
2028 got = pSHGetObjectCompatFlags(NULL, &clsid);
2029 ok(got == expected, "got 0x%08x, expected 0x%08x. Key %s\n", got, expected, keyA);
2031 RegCloseKey(clsid_key);
2039 const IOleCommandTargetVtbl *lpVtbl;
2041 } IOleCommandTargetImpl;
2043 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl;
2045 static IOleCommandTarget* IOleCommandTargetImpl_Construct(void)
2047 IOleCommandTargetImpl *obj;
2049 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2050 obj->lpVtbl = &IOleCommandTargetImpl_Vtbl;
2053 return (IOleCommandTarget*)obj;
2056 static HRESULT WINAPI IOleCommandTargetImpl_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppvObj)
2058 IOleCommandTargetImpl *This = (IOleCommandTargetImpl *)iface;
2060 if (IsEqualIID(riid, &IID_IUnknown) ||
2061 IsEqualIID(riid, &IID_IOleCommandTarget))
2068 IUnknown_AddRef(iface);
2072 return E_NOINTERFACE;
2075 static ULONG WINAPI IOleCommandTargetImpl_AddRef(IOleCommandTarget *iface)
2077 IOleCommandTargetImpl *This = (IOleCommandTargetImpl *)iface;
2078 return InterlockedIncrement(&This->ref);
2081 static ULONG WINAPI IOleCommandTargetImpl_Release(IOleCommandTarget *iface)
2083 IOleCommandTargetImpl *This = (IOleCommandTargetImpl *)iface;
2084 ULONG ref = InterlockedDecrement(&This->ref);
2088 HeapFree(GetProcessHeap(), 0, This);
2094 static HRESULT WINAPI IOleCommandTargetImpl_QueryStatus(
2095 IOleCommandTarget *iface, const GUID *group, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText)
2100 static HRESULT WINAPI IOleCommandTargetImpl_Exec(
2101 IOleCommandTarget *iface,
2102 const GUID *CmdGroup,
2108 add_call(&trace_got, 3, CmdGroup, (void*)(DWORD_PTR)nCmdID, (void*)(DWORD_PTR)nCmdexecopt, pvaIn, pvaOut);
2112 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl =
2114 IOleCommandTargetImpl_QueryInterface,
2115 IOleCommandTargetImpl_AddRef,
2116 IOleCommandTargetImpl_Release,
2117 IOleCommandTargetImpl_QueryStatus,
2118 IOleCommandTargetImpl_Exec
2122 const IServiceProviderVtbl *lpVtbl;
2124 } IServiceProviderImpl;
2127 const IProfferServiceVtbl *lpVtbl;
2129 } IProfferServiceImpl;
2132 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl;
2133 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl;
2135 static IServiceProvider* IServiceProviderImpl_Construct(void)
2137 IServiceProviderImpl *obj;
2139 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2140 obj->lpVtbl = &IServiceProviderImpl_Vtbl;
2143 return (IServiceProvider*)obj;
2146 static IProfferService* IProfferServiceImpl_Construct(void)
2148 IProfferServiceImpl *obj;
2150 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2151 obj->lpVtbl = &IProfferServiceImpl_Vtbl;
2154 return (IProfferService*)obj;
2157 static HRESULT WINAPI IServiceProviderImpl_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppvObj)
2159 IServiceProviderImpl *This = (IServiceProviderImpl *)iface;
2161 if (IsEqualIID(riid, &IID_IUnknown) ||
2162 IsEqualIID(riid, &IID_IServiceProvider))
2169 IUnknown_AddRef(iface);
2170 /* native uses redefined IID_IServiceProvider symbol, so we can't compare pointers */
2171 if (IsEqualIID(riid, &IID_IServiceProvider))
2172 add_call(&trace_got, 1, iface, &IID_IServiceProvider, 0, 0, 0);
2176 return E_NOINTERFACE;
2179 static ULONG WINAPI IServiceProviderImpl_AddRef(IServiceProvider *iface)
2181 IServiceProviderImpl *This = (IServiceProviderImpl *)iface;
2182 return InterlockedIncrement(&This->ref);
2185 static ULONG WINAPI IServiceProviderImpl_Release(IServiceProvider *iface)
2187 IServiceProviderImpl *This = (IServiceProviderImpl *)iface;
2188 ULONG ref = InterlockedDecrement(&This->ref);
2192 HeapFree(GetProcessHeap(), 0, This);
2198 static HRESULT WINAPI IServiceProviderImpl_QueryService(
2199 IServiceProvider *iface, REFGUID service, REFIID riid, void **ppv)
2201 /* native uses redefined pointer for IID_IOleCommandTarget, not one from uuid.lib */
2202 if (IsEqualIID(riid, &IID_IOleCommandTarget))
2204 add_call(&trace_got, 2, iface, service, &IID_IOleCommandTarget, 0, 0);
2205 *ppv = IOleCommandTargetImpl_Construct();
2207 if (IsEqualIID(riid, &IID_IProfferService))
2209 if (IsEqualIID(service, &IID_IProfferService))
2210 add_call(&trace_got, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2211 *ppv = IProfferServiceImpl_Construct();
2216 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl =
2218 IServiceProviderImpl_QueryInterface,
2219 IServiceProviderImpl_AddRef,
2220 IServiceProviderImpl_Release,
2221 IServiceProviderImpl_QueryService
2224 static void test_IUnknown_QueryServiceExec(void)
2226 IServiceProvider *provider = IServiceProviderImpl_Construct();
2227 static const GUID dummy_serviceid = { 0xdeadbeef };
2228 static const GUID dummy_groupid = { 0xbeefbeef };
2229 call_trace_t trace_expected;
2232 /* on <=W2K platforms same ordinal used for another export with different
2233 prototype, so skipping using this indirect condition */
2234 if (is_win2k_and_lower)
2236 win_skip("IUnknown_QueryServiceExec is not available\n");
2240 /* null source pointer */
2241 hr = pIUnknown_QueryServiceExec(NULL, &dummy_serviceid, &dummy_groupid, 0, 0, 0, 0);
2242 ok(hr == E_FAIL, "got 0x%08x\n", hr);
2245 IUnknown_QueryServiceExec( ptr1, serviceid, groupid, arg1, arg2, arg3, arg4);
2246 -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &prov );
2247 -> IServiceProvider_QueryService( prov, serviceid, &IID_IOleCommandTarget, &obj );
2248 -> IOleCommandTarget_Exec( obj, groupid, arg1, arg2, arg3, arg4 );
2250 init_call_trace(&trace_expected);
2252 add_call(&trace_expected, 1, provider, &IID_IServiceProvider, 0, 0, 0);
2253 add_call(&trace_expected, 2, provider, &dummy_serviceid, &IID_IOleCommandTarget, 0, 0);
2254 add_call(&trace_expected, 3, &dummy_groupid, (void*)0x1, (void*)0x2, (void*)0x3, (void*)0x4);
2256 init_call_trace(&trace_got);
2257 hr = pIUnknown_QueryServiceExec((IUnknown*)provider, &dummy_serviceid, &dummy_groupid, 0x1, 0x2, (void*)0x3, (void*)0x4);
2258 ok(hr == S_OK, "got 0x%08x\n", hr);
2260 ok_trace(&trace_expected, &trace_got);
2262 free_call_trace(&trace_expected);
2263 free_call_trace(&trace_got);
2265 IServiceProvider_Release(provider);
2269 static HRESULT WINAPI IProfferServiceImpl_QueryInterface(IProfferService *iface, REFIID riid, void **ppvObj)
2271 IProfferServiceImpl *This = (IProfferServiceImpl *)iface;
2273 if (IsEqualIID(riid, &IID_IUnknown) ||
2274 IsEqualIID(riid, &IID_IProfferService))
2278 else if (IsEqualIID(riid, &IID_IServiceProvider))
2280 *ppvObj = IServiceProviderImpl_Construct();
2281 add_call(&trace_got, 1, iface, &IID_IServiceProvider, 0, 0, 0);
2287 IUnknown_AddRef(iface);
2291 return E_NOINTERFACE;
2294 static ULONG WINAPI IProfferServiceImpl_AddRef(IProfferService *iface)
2296 IProfferServiceImpl *This = (IProfferServiceImpl *)iface;
2297 return InterlockedIncrement(&This->ref);
2300 static ULONG WINAPI IProfferServiceImpl_Release(IProfferService *iface)
2302 IProfferServiceImpl *This = (IProfferServiceImpl *)iface;
2303 ULONG ref = InterlockedDecrement(&This->ref);
2307 HeapFree(GetProcessHeap(), 0, This);
2313 static HRESULT WINAPI IProfferServiceImpl_ProfferService(IProfferService *iface,
2314 REFGUID service, IServiceProvider *pService, DWORD *pCookie)
2316 add_call(&trace_got, 3, service, pService, pCookie, 0, 0);
2320 static HRESULT WINAPI IProfferServiceImpl_RevokeService(IProfferService *iface, DWORD cookie)
2322 add_call(&trace_got, 4, (void*)(DWORD_PTR)cookie, 0, 0, 0, 0);
2326 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl =
2328 IProfferServiceImpl_QueryInterface,
2329 IProfferServiceImpl_AddRef,
2330 IProfferServiceImpl_Release,
2331 IProfferServiceImpl_ProfferService,
2332 IProfferServiceImpl_RevokeService
2335 static void test_IUnknown_ProfferService(void)
2337 IServiceProvider *provider = IServiceProviderImpl_Construct();
2338 IProfferService *proff = IProfferServiceImpl_Construct();
2339 static const GUID dummy_serviceid = { 0xdeadbeef };
2340 call_trace_t trace_expected;
2344 /* on <=W2K platforms same ordinal used for another export with different
2345 prototype, so skipping using this indirect condition */
2346 if (is_win2k_and_lower)
2348 win_skip("IUnknown_ProfferService is not available\n");
2352 /* null source pointer */
2353 hr = pIUnknown_ProfferService(NULL, &dummy_serviceid, 0, 0);
2354 ok(hr == E_FAIL, "got 0x%08x\n", hr);
2357 IUnknown_ProfferService( ptr1, serviceid, arg1, arg2);
2358 -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &provider );
2359 -> IServiceProvider_QueryService( provider, &IID_IProfferService, &IID_IProfferService, &proffer );
2361 if (service pointer not null):
2362 -> IProfferService_ProfferService( proffer, serviceid, arg1, arg2 );
2364 -> IProfferService_RevokeService( proffer, *arg2 );
2366 init_call_trace(&trace_expected);
2368 add_call(&trace_expected, 1, proff, &IID_IServiceProvider, 0, 0, 0);
2369 add_call(&trace_expected, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2370 add_call(&trace_expected, 3, &dummy_serviceid, provider, &cookie, 0, 0);
2372 init_call_trace(&trace_got);
2373 hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, provider, &cookie);
2374 ok(hr == S_OK, "got 0x%08x\n", hr);
2376 ok_trace(&trace_expected, &trace_got);
2377 free_call_trace(&trace_got);
2378 free_call_trace(&trace_expected);
2380 /* same with ::Revoke path */
2381 init_call_trace(&trace_expected);
2383 add_call(&trace_expected, 1, proff, &IID_IServiceProvider, 0, 0, 0);
2384 add_call(&trace_expected, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2385 add_call(&trace_expected, 4, (void*)(DWORD_PTR)cookie, 0, 0, 0, 0);
2387 init_call_trace(&trace_got);
2388 hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, 0, &cookie);
2389 ok(hr == S_OK, "got 0x%08x\n", hr);
2390 ok_trace(&trace_expected, &trace_got);
2391 free_call_trace(&trace_got);
2392 free_call_trace(&trace_expected);
2394 IServiceProvider_Release(provider);
2395 IProfferService_Release(proff);
2398 static void test_SHCreateWorkerWindowA(void)
2406 if (is_win2k_and_lower)
2408 win_skip("SHCreateWorkerWindowA not available\n");
2412 hwnd = pSHCreateWorkerWindowA(0, NULL, 0, 0, 0, 0);
2413 ok(hwnd != 0, "expected window\n");
2415 GetClassName(hwnd, classA, 20);
2416 ok(lstrcmpA(classA, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA);
2418 ret = GetWindowLongPtrA(hwnd, 0);
2419 ok(ret == 0, "got %ld\n", ret);
2422 memset(&cliA, 0, sizeof(cliA));
2423 res = GetClassInfoA(GetModuleHandle("shlwapi.dll"), "WorkerA", &cliA);
2424 ok(res, "failed to get class info\n");
2425 ok(cliA.style == 0, "got 0x%08x\n", cliA.style);
2426 ok(cliA.cbClsExtra == 0, "got %d\n", cliA.cbClsExtra);
2427 ok(cliA.cbWndExtra == sizeof(LONG_PTR), "got %d\n", cliA.cbWndExtra);
2428 ok(cliA.lpszMenuName == 0, "got %s\n", cliA.lpszMenuName);
2430 DestroyWindow(hwnd);
2432 /* set extra bytes */
2433 hwnd = pSHCreateWorkerWindowA(0, NULL, 0, 0, 0, 0xdeadbeef);
2434 ok(hwnd != 0, "expected window\n");
2436 GetClassName(hwnd, classA, 20);
2437 ok(lstrcmpA(classA, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA);
2439 ret = GetWindowLongPtrA(hwnd, 0);
2440 ok(ret == 0xdeadbeef, "got %ld\n", ret);
2443 ret = GetWindowLongA(hwnd, GWL_EXSTYLE);
2444 ok(ret == WS_EX_WINDOWEDGE ||
2445 ret == (WS_EX_WINDOWEDGE|WS_EX_LAYOUTRTL) /* systems with RTL locale */, "0x%08lx\n", ret);
2447 DestroyWindow(hwnd);
2449 hwnd = pSHCreateWorkerWindowA(0, NULL, WS_EX_TOOLWINDOW, 0, 0, 0);
2450 ret = GetWindowLongA(hwnd, GWL_EXSTYLE);
2451 ok(ret == (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW) ||
2452 ret == (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW|WS_EX_LAYOUTRTL) /* systems with RTL locale */, "0x%08lx\n", ret);
2453 DestroyWindow(hwnd);
2456 static HRESULT WINAPI SF_QueryInterface(IShellFolder *iface,
2457 REFIID riid, void **ppv)
2459 /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */
2460 ok(!IsEqualGUID(&IID_IShellFolder, riid),
2461 "Unexpected QI for IShellFolder\n");
2462 return E_NOINTERFACE;
2465 static ULONG WINAPI SF_AddRef(IShellFolder *iface)
2470 static ULONG WINAPI SF_Release(IShellFolder *iface)
2475 static HRESULT WINAPI SF_ParseDisplayName(IShellFolder *iface,
2476 HWND owner, LPBC reserved, LPOLESTR displayName, ULONG *eaten,
2477 LPITEMIDLIST *idl, ULONG *attr)
2479 ok(0, "Didn't expect ParseDisplayName\n");
2483 static HRESULT WINAPI SF_EnumObjects(IShellFolder *iface,
2484 HWND owner, SHCONTF flags, IEnumIDList **enm)
2486 *enm = (IEnumIDList*)0xcafebabe;
2490 static HRESULT WINAPI SF_BindToObject(IShellFolder *iface,
2491 LPCITEMIDLIST idl, LPBC reserved, REFIID riid, void **obj)
2493 ok(0, "Didn't expect BindToObject\n");
2497 static HRESULT WINAPI SF_BindToStorage(IShellFolder *iface,
2498 LPCITEMIDLIST idl, LPBC reserved, REFIID riid, void **obj)
2500 ok(0, "Didn't expect BindToStorage\n");
2504 static HRESULT WINAPI SF_CompareIDs(IShellFolder *iface,
2505 LPARAM lparam, LPCITEMIDLIST idl1, LPCITEMIDLIST idl2)
2507 ok(0, "Didn't expect CompareIDs\n");
2511 static HRESULT WINAPI SF_CreateViewObject(IShellFolder *iface,
2512 HWND owner, REFIID riid, void **out)
2514 ok(0, "Didn't expect CreateViewObject\n");
2518 static HRESULT WINAPI SF_GetAttributesOf(IShellFolder *iface,
2519 UINT cidl, LPCITEMIDLIST *idl, SFGAOF *inOut)
2521 ok(0, "Didn't expect GetAttributesOf\n");
2525 static HRESULT WINAPI SF_GetUIObjectOf(IShellFolder *iface,
2526 HWND owner, UINT cidl, LPCITEMIDLIST *idls, REFIID riid, UINT *inOut,
2529 ok(0, "Didn't expect GetUIObjectOf\n");
2533 static HRESULT WINAPI SF_GetDisplayNameOf(IShellFolder *iface,
2534 LPCITEMIDLIST idl, SHGDNF flags, STRRET *name)
2536 ok(0, "Didn't expect GetDisplayNameOf\n");
2540 static HRESULT WINAPI SF_SetNameOf(IShellFolder *iface,
2541 HWND hwnd, LPCITEMIDLIST idl, LPCOLESTR name, SHGDNF flags,
2542 LPITEMIDLIST *idlOut)
2544 ok(0, "Didn't expect SetNameOf\n");
2548 static IShellFolderVtbl ShellFolderVtbl = {
2552 SF_ParseDisplayName,
2557 SF_CreateViewObject,
2560 SF_GetDisplayNameOf,
2564 static IShellFolder ShellFolder = { &ShellFolderVtbl };
2566 static void test_SHIShellFolder_EnumObjects(void)
2570 IShellFolder *folder;
2572 if(!pSHIShellFolder_EnumObjects || is_win2k_and_lower){
2573 win_skip("SHIShellFolder_EnumObjects not available\n");
2578 /* NULL object crashes on Windows */
2579 hres = pSHIShellFolder_EnumObjects(NULL, NULL, 0, NULL);
2582 /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */
2583 enm = (IEnumIDList*)0xdeadbeef;
2584 hres = pSHIShellFolder_EnumObjects(&ShellFolder, NULL, 0, &enm);
2585 ok(hres == S_OK, "SHIShellFolder_EnumObjects failed: 0x%08x\n", hres);
2586 ok(enm == (IEnumIDList*)0xcafebabe, "Didn't get expected enumerator location, instead: %p\n", enm);
2588 /* SHIShellFolder_EnumObjects isn't strict about the IShellFolder object */
2589 hres = pSHGetDesktopFolder(&folder);
2590 ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
2593 hres = pSHIShellFolder_EnumObjects(folder, NULL, 0, &enm);
2594 ok(hres == S_OK, "SHIShellFolder_EnumObjects failed: 0x%08x\n", hres);
2595 ok(enm != NULL, "Didn't get an enumerator\n");
2597 IEnumIDList_Release(enm);
2599 IShellFolder_Release(folder);
2602 static void write_inifile(LPCWSTR filename)
2607 static const char data[] =
2610 "AnotherKey=asdf\r\n";
2612 file = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
2613 if(file == INVALID_HANDLE_VALUE)
2616 WriteFile(file, data, sizeof(data), &written, NULL);
2621 #define verify_inifile(f, e) r_verify_inifile(__LINE__, f, e)
2622 static void r_verify_inifile(unsigned l, LPCWSTR filename, LPCSTR exp)
2628 file = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
2629 if(file == INVALID_HANDLE_VALUE)
2632 ReadFile(file, buf, sizeof(buf) * sizeof(CHAR), &read, NULL);
2637 ok_(__FILE__,l)(!strcmp(buf, exp), "Expected:\n%s\nGot:\n%s\n", exp,
2641 static void test_SHGetIniString(void)
2644 WCHAR out[64] = {0};
2646 static const WCHAR TestAppW[] = {'T','e','s','t','A','p','p',0};
2647 static const WCHAR TestIniW[] = {'C',':','\\','t','e','s','t','.','i','n','i',0};
2648 static const WCHAR AKeyW[] = {'A','K','e','y',0};
2649 static const WCHAR AnotherKeyW[] = {'A','n','o','t','h','e','r','K','e','y',0};
2650 static const WCHAR JunkKeyW[] = {'J','u','n','k','K','e','y',0};
2652 if(!pSHGetIniStringW || is_win2k_and_lower){
2653 win_skip("SHGetIniStringW is not available\n");
2657 write_inifile(TestIniW);
2660 /* these crash on Windows */
2661 ret = pSHGetIniStringW(NULL, NULL, NULL, 0, NULL);
2662 ret = pSHGetIniStringW(NULL, AKeyW, out, sizeof(out), TestIniW);
2663 ret = pSHGetIniStringW(TestAppW, AKeyW, NULL, sizeof(out), TestIniW);
2666 ret = pSHGetIniStringW(TestAppW, AKeyW, out, 0, TestIniW);
2667 ok(ret == 0, "SHGetIniStringW should have given 0, instead: %d\n", ret);
2669 /* valid arguments */
2670 ret = pSHGetIniStringW(TestAppW, NULL, out, sizeof(out), TestIniW);
2671 ok(broken(ret == 0) || /* win 98 */
2672 ret == 4, "SHGetIniStringW should have given 4, instead: %d\n", ret);
2673 ok(!lstrcmpW(out, AKeyW), "Expected %s, got: %s\n",
2674 wine_dbgstr_w(AKeyW), wine_dbgstr_w(out));
2676 ret = pSHGetIniStringW(TestAppW, AKeyW, out, sizeof(out), TestIniW);
2677 ok(broken(ret == 0) || /* win 98 */
2678 ret == 1, "SHGetIniStringW should have given 1, instead: %d\n", ret);
2679 ok(broken(*out == 0) || /*win 98 */
2680 !strcmp_wa(out, "1"), "Expected L\"1\", got: %s\n", wine_dbgstr_w(out));
2682 ret = pSHGetIniStringW(TestAppW, AnotherKeyW, out, sizeof(out), TestIniW);
2683 ok(broken(ret == 0) || /* win 98 */
2684 ret == 4, "SHGetIniStringW should have given 4, instead: %d\n", ret);
2685 ok(broken(*out == 0) || /* win 98 */
2686 !strcmp_wa(out, "asdf"), "Expected L\"asdf\", got: %s\n", wine_dbgstr_w(out));
2688 ret = pSHGetIniStringW(TestAppW, JunkKeyW, out, sizeof(out), TestIniW);
2689 ok(ret == 0, "SHGetIniStringW should have given 0, instead: %d\n", ret);
2690 ok(*out == 0, "Expected L\"\", got: %s\n", wine_dbgstr_w(out));
2692 DeleteFileW(TestIniW);
2695 static void test_SHSetIniString(void)
2699 static const WCHAR TestAppW[] = {'T','e','s','t','A','p','p',0};
2700 static const WCHAR AnotherAppW[] = {'A','n','o','t','h','e','r','A','p','p',0};
2701 static const WCHAR TestIniW[] = {'C',':','\\','t','e','s','t','.','i','n','i',0};
2702 static const WCHAR AKeyW[] = {'A','K','e','y',0};
2703 static const WCHAR NewKeyW[] = {'N','e','w','K','e','y',0};
2704 static const WCHAR AValueW[] = {'A','V','a','l','u','e',0};
2706 if(!pSHSetIniStringW || is_win2k_and_lower){
2707 win_skip("SHSetIniStringW is not available\n");
2711 write_inifile(TestIniW);
2713 ret = pSHSetIniStringW(TestAppW, AKeyW, AValueW, TestIniW);
2714 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2715 todo_wine /* wine sticks an extra \r\n at the end of the file */
2716 verify_inifile(TestIniW, "[TestApp]\r\nAKey=AValue\r\nAnotherKey=asdf\r\n");
2718 ret = pSHSetIniStringW(TestAppW, AKeyW, NULL, TestIniW);
2719 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2720 verify_inifile(TestIniW, "[TestApp]\r\nAnotherKey=asdf\r\n");
2722 ret = pSHSetIniStringW(AnotherAppW, NewKeyW, AValueW, TestIniW);
2723 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2724 verify_inifile(TestIniW, "[TestApp]\r\nAnotherKey=asdf\r\n[AnotherApp]\r\nNewKey=AValue\r\n");
2726 ret = pSHSetIniStringW(TestAppW, NULL, AValueW, TestIniW);
2727 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2728 verify_inifile(TestIniW, "[AnotherApp]\r\nNewKey=AValue\r\n");
2730 DeleteFileW(TestIniW);
2733 enum _shellkey_flags {
2734 SHKEY_Root_HKCU = 0x1,
2735 SHKEY_Root_HKLM = 0x2,
2736 SHKEY_Key_Explorer = 0x00,
2737 SHKEY_Key_Shell = 0x10,
2738 SHKEY_Key_ShellNoRoam = 0x20,
2739 SHKEY_Key_Classes = 0x30,
2740 SHKEY_Subkey_Default = 0x0000,
2741 SHKEY_Subkey_ResourceName = 0x1000,
2742 SHKEY_Subkey_Handlers = 0x2000,
2743 SHKEY_Subkey_Associations = 0x3000,
2744 SHKEY_Subkey_Volatile = 0x4000,
2745 SHKEY_Subkey_MUICache = 0x5000,
2746 SHKEY_Subkey_FileExts = 0x6000
2749 static void test_SHGetShellKey(void)
2751 static const WCHAR ShellFoldersW[] = { 'S','h','e','l','l',' ','F','o','l','d','e','r','s',0 };
2752 static const WCHAR WineTestW[] = { 'W','i','n','e','T','e','s','t',0 };
2754 void *pPathBuildRootW = GetProcAddress(hShlwapi, "PathBuildRootW");
2755 DWORD *alloc_data, data, size;
2759 if (!pSHGetShellKey)
2761 win_skip("SHGetShellKey(ordinal 491) isn't available\n");
2766 if (pPathBuildRootW && pPathBuildRootW == pSHGetShellKey)
2768 win_skip("SHGetShellKey(ordinal 491) used for PathBuildRootW\n");
2772 if (is_win9x || is_win2k_and_lower)
2774 win_skip("Ordinal 491 used for another call, skipping SHGetShellKey tests\n");
2778 /* Vista+ limits SHKEY enumeration values */
2779 SetLastError(0xdeadbeef);
2780 hkey = pSHGetShellKey(SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2783 /* Tests not working on Vista+ */
2786 hkey = pSHGetShellKey(SHKEY_Root_HKLM|SHKEY_Key_Classes, NULL, FALSE);
2787 ok(hkey != NULL, "hkey = NULL\n");
2791 hkey = pSHGetShellKey(SHKEY_Root_HKCU|SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2792 ok(hkey != NULL, "hkey = NULL\n");
2795 hkey = pSHGetShellKey(SHKEY_Root_HKLM|SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2796 ok(hkey != NULL, "hkey = NULL\n");
2799 hkey = pSHGetShellKey(SHKEY_Root_HKLM, WineTestW, FALSE);
2800 ok(hkey == NULL, "hkey != NULL\n");
2802 hkey = pSHGetShellKey(SHKEY_Root_HKLM, WineTestW, TRUE);
2803 ok(hkey != NULL, "Can't create key\n");
2806 hkey = pSHGetShellKey(SHKEY_Root_HKLM, NULL, FALSE);
2807 ok(hkey != NULL, "Can't create key\n");
2808 ok(SUCCEEDED(RegDeleteKeyW(hkey, WineTestW)), "Can't delte key\n");
2811 if (!pSKGetValueW || !pSKSetValueW || !pSKDeleteValueW || !pSKAllocValueW)
2813 win_skip("SKGetValueW, SKSetValueW, SKDeleteValueW or SKAllocValueW not available\n");
2817 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
2818 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres);
2821 hres = pSKSetValueW(SHKEY_Root_HKLM, WineTestW, NULL, REG_DWORD, &data, sizeof(DWORD));
2822 ok(hres == S_OK, "hres = %x\n", hres);
2825 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, NULL, &size);
2826 ok(hres == S_OK, "hres = %x\n", hres);
2827 ok(size == sizeof(DWORD), "size = %d\n", size);
2830 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
2831 ok(hres == S_OK, "hres = %x\n", hres);
2832 ok(size == sizeof(DWORD), "size = %d\n", size);
2833 ok(data == 1234, "data = %d\n", data);
2835 hres = pSKAllocValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, (void**)&alloc_data, &size);
2836 ok(hres == S_OK, "hres= %x\n", hres);
2837 ok(size == sizeof(DWORD), "size = %d\n", size);
2838 ok(*alloc_data == 1234, "*alloc_data = %d\n", *alloc_data);
2839 LocalFree(alloc_data);
2841 hres = pSKDeleteValueW(SHKEY_Root_HKLM, WineTestW, NULL);
2842 ok(hres == S_OK, "hres = %x\n", hres);
2844 hres = pSKDeleteValueW(SHKEY_Root_HKLM, WineTestW, NULL);
2845 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres);
2847 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
2848 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres);
2850 hkey = pSHGetShellKey(SHKEY_Root_HKLM, NULL, FALSE);
2851 ok(hkey != NULL, "Can't create key\n");
2852 ok(SUCCEEDED(RegDeleteKeyW(hkey, WineTestW)), "Can't delte key\n");
2856 static void init_pointers(void)
2858 #define MAKEFUNC(f, ord) (p##f = (void*)GetProcAddress(hShlwapi, (LPSTR)(ord)))
2859 MAKEFUNC(SHAllocShared, 7);
2860 MAKEFUNC(SHLockShared, 8);
2861 MAKEFUNC(SHUnlockShared, 9);
2862 MAKEFUNC(SHFreeShared, 10);
2863 MAKEFUNC(GetAcceptLanguagesA, 14);
2864 MAKEFUNC(SHSetWindowBits, 165);
2865 MAKEFUNC(ConnectToConnectionPoint, 168);
2866 MAKEFUNC(SHSearchMapInt, 198);
2867 MAKEFUNC(SHCreateWorkerWindowA, 257);
2868 MAKEFUNC(GUIDFromStringA, 269);
2869 MAKEFUNC(SHPackDispParams, 282);
2870 MAKEFUNC(IConnectionPoint_InvokeWithCancel, 283);
2871 MAKEFUNC(IConnectionPoint_SimpleInvoke, 284);
2872 MAKEFUNC(SHGetIniStringW, 294);
2873 MAKEFUNC(SHSetIniStringW, 295);
2874 MAKEFUNC(SHFormatDateTimeA, 353);
2875 MAKEFUNC(SHFormatDateTimeW, 354);
2876 MAKEFUNC(SHIShellFolder_EnumObjects, 404);
2877 MAKEFUNC(SHGetObjectCompatFlags, 476);
2878 MAKEFUNC(IUnknown_QueryServiceExec, 484);
2879 MAKEFUNC(SHGetShellKey, 491);
2880 MAKEFUNC(SHPropertyBag_ReadLONG, 496);
2881 MAKEFUNC(IUnknown_ProfferService, 514);
2882 MAKEFUNC(SKGetValueW, 516);
2883 MAKEFUNC(SKSetValueW, 517);
2884 MAKEFUNC(SKDeleteValueW, 518);
2885 MAKEFUNC(SKAllocValueW, 519);
2891 hShlwapi = GetModuleHandleA("shlwapi.dll");
2892 is_win2k_and_lower = GetProcAddress(hShlwapi, "StrChrNW") == 0;
2893 is_win9x = GetProcAddress(hShlwapi, (LPSTR)99) == 0; /* StrCpyNXA */
2895 /* SHCreateStreamOnFileEx was introduced in shlwapi v6.0 */
2896 if(!GetProcAddress(hShlwapi, "SHCreateStreamOnFileEx")){
2897 win_skip("Too old shlwapi version\n");
2903 hmlang = LoadLibraryA("mlang.dll");
2904 pLcidToRfc1766A = (void *)GetProcAddress(hmlang, "LcidToRfc1766A");
2906 hshell32 = LoadLibraryA("shell32.dll");
2907 pSHGetDesktopFolder = (void *)GetProcAddress(hshell32, "SHGetDesktopFolder");
2909 test_GetAcceptLanguagesA();
2910 test_SHSearchMapInt();
2911 test_alloc_shared();
2913 test_GetShellSecurityDescriptor();
2914 test_SHPackDispParams();
2915 test_IConnectionPoint();
2916 test_SHPropertyBag_ReadLONG();
2917 test_SHSetWindowBits();
2918 test_SHFormatDateTimeA();
2919 test_SHFormatDateTimeW();
2920 test_SHGetObjectCompatFlags();
2921 test_IUnknown_QueryServiceExec();
2922 test_IUnknown_ProfferService();
2923 test_SHCreateWorkerWindowA();
2924 test_SHIShellFolder_EnumObjects();
2925 test_SHGetIniString();
2926 test_SHSetIniString();
2927 test_SHGetShellKey();
2929 FreeLibrary(hshell32);
2930 FreeLibrary(hmlang);