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
23 #include "wine/test.h"
35 /* Function ptrs for ordinal calls */
36 static HMODULE hShlwapi;
37 static int (WINAPI *pSHSearchMapInt)(const int*,const int*,int,int);
38 static HRESULT (WINAPI *pGetAcceptLanguagesA)(LPSTR,LPDWORD);
40 static HANDLE (WINAPI *pSHAllocShared)(LPCVOID,DWORD,DWORD);
41 static LPVOID (WINAPI *pSHLockShared)(HANDLE,DWORD);
42 static BOOL (WINAPI *pSHUnlockShared)(LPVOID);
43 static BOOL (WINAPI *pSHFreeShared)(HANDLE,DWORD);
44 static HRESULT(WINAPIV *pSHPackDispParams)(DISPPARAMS*,VARIANTARG*,UINT,...);
45 static HRESULT(WINAPI *pIConnectionPoint_SimpleInvoke)(IConnectionPoint*,DISPID,DISPPARAMS*);
46 static HRESULT(WINAPI *pIConnectionPoint_InvokeWithCancel)(IConnectionPoint*,DISPID,DISPPARAMS*,DWORD,DWORD);
47 static HRESULT(WINAPI *pConnectToConnectionPoint)(IUnknown*,REFIID,BOOL,IUnknown*, LPDWORD,IConnectionPoint **);
48 static HRESULT(WINAPI *pSHPropertyBag_ReadLONG)(IPropertyBag *,LPCWSTR,LPLONG);
49 static LONG (WINAPI *pSHSetWindowBits)(HWND, INT, UINT, UINT);
50 static INT (WINAPI *pSHFormatDateTimeA)(const FILETIME UNALIGNED*, DWORD*, LPSTR, UINT);
51 static INT (WINAPI *pSHFormatDateTimeW)(const FILETIME UNALIGNED*, DWORD*, LPWSTR, UINT);
52 static DWORD (WINAPI *pSHGetObjectCompatFlags)(IUnknown*, const CLSID*);
53 static BOOL (WINAPI *pGUIDFromStringA)(LPSTR, CLSID *);
54 static HRESULT (WINAPI *pIUnknown_QueryServiceExec)(IUnknown*, REFIID, const GUID*, DWORD, DWORD, VARIANT*, VARIANT*);
55 static HRESULT (WINAPI *pIUnknown_ProfferService)(IUnknown*, REFGUID, IServiceProvider*, DWORD*);
57 static HMODULE hmlang;
58 static HRESULT (WINAPI *pLcidToRfc1766A)(LCID, LPSTR, INT);
60 static const CHAR ie_international[] = {
61 'S','o','f','t','w','a','r','e','\\',
62 'M','i','c','r','o','s','o','f','t','\\',
63 'I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r','\\',
64 'I','n','t','e','r','n','a','t','i','o','n','a','l',0};
65 static const CHAR acceptlanguage[] = {
66 'A','c','c','e','p','t','L','a','n','g','u','a','g','e',0};
79 static void init_call_trace(call_trace_t *ctrace)
83 ctrace->calls = HeapAlloc(GetProcessHeap(), 0, sizeof(call_entry_t) * ctrace->alloc);
86 static void free_call_trace(const call_trace_t *ctrace)
88 HeapFree(GetProcessHeap(), 0, ctrace->calls);
91 static void add_call(call_trace_t *ctrace, int id, const void *arg0,
92 const void *arg1, const void *arg2, const void *arg3, const void *arg4)
103 if (ctrace->count == ctrace->alloc)
106 ctrace->calls = HeapReAlloc(GetProcessHeap(),0, ctrace->calls, ctrace->alloc*sizeof(call_entry_t));
109 ctrace->calls[ctrace->count++] = call;
112 static void ok_trace_(call_trace_t *texpected, call_trace_t *tgot, int line)
114 if (texpected->count == tgot->count)
118 for (i = 0; i < texpected->count; i++)
120 call_entry_t *expected = &texpected->calls[i];
121 call_entry_t *got = &tgot->calls[i];
124 ok_(__FILE__, line)(expected->id == got->id, "got different ids %d: %d, %d\n", i+1, expected->id, got->id);
126 for (j = 0; j < 5; j++)
128 ok_(__FILE__, line)(expected->args[j] == got->args[j], "got different args[%d] for %d: %p, %p\n", j, i+1,
129 expected->args[j], got->args[j]);
134 ok_(__FILE__, line)(0, "traces length mismatch\n");
137 #define ok_trace(a, b) ok_trace_(a, b, __LINE__)
139 /* trace of actually made calls */
140 static call_trace_t trace_got;
142 static void test_GetAcceptLanguagesA(void)
144 static LPCSTR table[] = {"de,en-gb;q=0.7,en;q=0.3",
145 "de,en;q=0.3,en-gb;q=0.7", /* sorting is ignored */
146 "winetest", /* content is ignored */
156 LONG res_query = ERROR_SUCCESS;
159 DWORD maxlen = sizeof(buffer) - 2;
165 if (!pGetAcceptLanguagesA) {
166 win_skip("GetAcceptLanguagesA is not available\n");
170 lcid = GetUserDefaultLCID();
172 /* Get the original Value */
173 lres = RegOpenKeyA(HKEY_CURRENT_USER, ie_international, &hroot);
175 skip("RegOpenKey(%s) failed: %d\n", ie_international, lres);
178 len = sizeof(original);
180 res_query = RegQueryValueExA(hroot, acceptlanguage, 0, NULL, (PBYTE)original, &len);
182 RegDeleteValue(hroot, acceptlanguage);
184 /* Some windows versions use "lang-COUNTRY" as default */
185 memset(language, 0, sizeof(language));
186 len = GetLocaleInfoA(lcid, LOCALE_SISO639LANGNAME, language, sizeof(language));
189 lstrcat(language, "-");
190 memset(buffer, 0, sizeof(buffer));
191 len = GetLocaleInfoA(lcid, LOCALE_SISO3166CTRYNAME, buffer, sizeof(buffer) - len - 1);
192 lstrcat(language, buffer);
196 /* LOCALE_SNAME has additional parts in some languages. Try only as last chance */
197 memset(language, 0, sizeof(language));
198 len = GetLocaleInfoA(lcid, LOCALE_SNAME, language, sizeof(language));
201 /* get the default value */
203 memset(buffer, '#', maxlen);
205 hr = pGetAcceptLanguagesA( buffer, &len);
208 win_skip("GetAcceptLanguagesA failed with 0x%x\n", hr);
209 goto restore_original;
212 if (lstrcmpA(buffer, language)) {
213 /* some windows versions use "lang" or "lang-country" as default */
215 if (pLcidToRfc1766A) {
216 hr = pLcidToRfc1766A(lcid, language, sizeof(language));
217 ok(hr == S_OK, "LcidToRfc1766A returned 0x%x and %s\n", hr, language);
221 ok(!lstrcmpA(buffer, language),
222 "have '%s' (searching for '%s')\n", language, buffer);
224 if (lstrcmpA(buffer, language)) {
225 win_skip("no more ideas, how to build the default language '%s'\n", buffer);
226 goto restore_original;
229 trace("detected default: %s\n", language);
230 while ((entry = table[i])) {
232 exactsize = lstrlenA(entry);
234 lres = RegSetValueExA(hroot, acceptlanguage, 0, REG_SZ, (const BYTE *) entry, exactsize + 1);
235 ok(!lres, "got %d for RegSetValueExA: %s\n", lres, entry);
237 /* len includes space for the terminating 0 before vista/w2k8 */
239 memset(buffer, '#', maxlen);
241 hr = pGetAcceptLanguagesA( buffer, &len);
242 ok(((hr == E_INVALIDARG) && (len == 0)) ||
244 ((len == exactsize) || (len == exactsize+1)) &&
245 !lstrcmpA(buffer, entry)),
246 "+2_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
249 memset(buffer, '#', maxlen);
251 hr = pGetAcceptLanguagesA( buffer, &len);
252 ok(((hr == E_INVALIDARG) && (len == 0)) ||
254 ((len == exactsize) || (len == exactsize+1)) &&
255 !lstrcmpA(buffer, entry)),
256 "+1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
259 memset(buffer, '#', maxlen);
261 hr = pGetAcceptLanguagesA( buffer, &len);
263 /* There is no space for the string in the registry.
264 When the buffer is large enough, the default language is returned
266 When the buffer is too small for that fallback, win7_32 and w2k8_64
267 and above fail with HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), but
268 recent os succeed and return a partial result while
269 older os succeed and overflow the buffer */
271 ok(((hr == E_INVALIDARG) && (len == 0)) ||
272 (((hr == S_OK) && !lstrcmpA(buffer, language) && (len == lstrlenA(language))) ||
273 ((hr == S_OK) && !memcmp(buffer, language, len)) ||
274 ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len)),
275 "==_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
279 memset(buffer, '#', maxlen);
281 hr = pGetAcceptLanguagesA( buffer, &len);
282 ok(((hr == E_INVALIDARG) && (len == 0)) ||
283 (((hr == S_OK) && !lstrcmpA(buffer, language) && (len == lstrlenA(language))) ||
284 ((hr == S_OK) && !memcmp(buffer, language, len)) ||
285 ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len)),
286 "-1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
290 memset(buffer, '#', maxlen);
292 hr = pGetAcceptLanguagesA( buffer, &len);
293 ok(((hr == E_INVALIDARG) && (len == 0)) ||
294 (((hr == S_OK) && !lstrcmpA(buffer, language) && (len == lstrlenA(language))) ||
295 ((hr == S_OK) && !memcmp(buffer, language, len)) ||
296 ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len)),
297 "=1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
300 hr = pGetAcceptLanguagesA( NULL, &len);
302 /* w2k3 and below: E_FAIL and untouched len,
303 since w2k8: S_OK and needed size (excluding 0) */
304 ok( ((hr == S_OK) && (len == exactsize)) ||
305 ((hr == E_FAIL) && (len == maxlen)),
306 "NULL,max #%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
311 /* without a value in the registry, a default language is returned */
312 RegDeleteValue(hroot, acceptlanguage);
315 memset(buffer, '#', maxlen);
317 hr = pGetAcceptLanguagesA( buffer, &len);
318 ok( ((hr == S_OK) && (len == lstrlenA(language))),
319 "max: got 0x%x with %d and %s (expected S_OK with %d and '%s'\n",
320 hr, len, buffer, lstrlenA(language), language);
323 memset(buffer, '#', maxlen);
325 hr = pGetAcceptLanguagesA( buffer, &len);
326 ok( (((hr == S_OK) || (hr == E_INVALIDARG)) && !memcmp(buffer, language, len)) ||
327 ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len),
328 "=2: got 0x%x with %d and %s\n", hr, len, buffer);
331 memset(buffer, '#', maxlen);
333 hr = pGetAcceptLanguagesA( buffer, &len);
334 /* When the buffer is too small, win7_32 and w2k8_64 and above fail with
335 HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), other versions suceed
336 and return a partial 0 terminated result while other versions
337 fail with E_INVALIDARG and return a partial unterminated result */
338 ok( (((hr == S_OK) || (hr == E_INVALIDARG)) && !memcmp(buffer, language, len)) ||
339 ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len),
340 "=1: got 0x%x with %d and %s\n", hr, len, buffer);
343 memset(buffer, '#', maxlen);
345 hr = pGetAcceptLanguagesA( buffer, &len);
346 /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG */
347 ok((hr == E_FAIL) || (hr == E_INVALIDARG),
348 "got 0x%x (expected E_FAIL or E_INVALIDARG)\n", hr);
350 memset(buffer, '#', maxlen);
352 hr = pGetAcceptLanguagesA( buffer, NULL);
353 /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG */
354 ok((hr == E_FAIL) || (hr == E_INVALIDARG),
355 "got 0x%x (expected E_FAIL or E_INVALIDARG)\n", hr);
358 hr = pGetAcceptLanguagesA( NULL, NULL);
359 /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG */
360 ok((hr == E_FAIL) || (hr == E_INVALIDARG),
361 "got 0x%x (expected E_FAIL or E_INVALIDARG)\n", hr);
365 len = lstrlenA(original);
366 lres = RegSetValueExA(hroot, acceptlanguage, 0, REG_SZ, (const BYTE *) original, len ? len + 1: 0);
367 ok(!lres, "RegSetValueEx(%s) failed: %d\n", original, lres);
371 RegDeleteValue(hroot, acceptlanguage);
376 static void test_SHSearchMapInt(void)
378 int keys[8], values[8];
381 if (!pSHSearchMapInt)
384 memset(keys, 0, sizeof(keys));
385 memset(values, 0, sizeof(values));
386 keys[0] = 99; values[0] = 101;
388 /* NULL key/value lists crash native, so skip testing them */
391 i = pSHSearchMapInt(keys, values, 1, keys[0]);
392 ok(i == values[0], "Len 1, expected %d, got %d\n", values[0], i);
394 /* Key doesn't exist */
395 i = pSHSearchMapInt(keys, values, 1, 100);
396 ok(i == -1, "Len 1 - bad key, expected -1, got %d\n", i);
398 /* Len = 0 => not found */
399 i = pSHSearchMapInt(keys, values, 0, keys[0]);
400 ok(i == -1, "Len 1 - passed len 0, expected -1, got %d\n", i);
402 /* 2 elements, len = 1 */
403 keys[1] = 98; values[1] = 102;
404 i = pSHSearchMapInt(keys, values, 1, keys[1]);
405 ok(i == -1, "Len 1 - array len 2, expected -1, got %d\n", i);
407 /* 2 elements, len = 2 */
408 i = pSHSearchMapInt(keys, values, 2, keys[1]);
409 ok(i == values[1], "Len 2, expected %d, got %d\n", values[1], i);
411 /* Searches forward */
412 keys[2] = 99; values[2] = 103;
413 i = pSHSearchMapInt(keys, values, 3, keys[0]);
414 ok(i == values[0], "Len 3, expected %d, got %d\n", values[0], i);
417 static void test_alloc_shared(void)
425 procid=GetCurrentProcessId();
426 hmem=pSHAllocShared(NULL,10,procid);
427 ok(hmem!=NULL,"SHAllocShared(NULL...) failed: %u\n", GetLastError());
428 ret = pSHFreeShared(hmem, procid);
429 ok( ret, "SHFreeShared failed: %u\n", GetLastError());
432 hmem=pSHAllocShared(&val,4,procid);
433 ok(hmem!=NULL,"SHAllocShared(NULL...) failed: %u\n", GetLastError());
435 p=pSHLockShared(hmem,procid);
436 ok(p!=NULL,"SHLockShared failed: %u\n", GetLastError());
438 ok(*p==val,"Wrong value in shared memory: %d instead of %d\n",*p,val);
439 ret = pSHUnlockShared(p);
440 ok( ret, "SHUnlockShared failed: %u\n", GetLastError());
442 ret = pSHFreeShared(hmem, procid);
443 ok( ret, "SHFreeShared failed: %u\n", GetLastError());
446 static void test_fdsa(void)
450 DWORD num_items; /* Number of elements inserted */
451 void *mem; /* Ptr to array */
452 DWORD blocks_alloced; /* Number of elements allocated */
453 BYTE inc; /* Number of elements to grow by when we need to expand */
454 BYTE block_size; /* Size in bytes of an element */
455 BYTE flags; /* Flags */
458 BOOL (WINAPI *pFDSA_Initialize)(DWORD block_size, DWORD inc, FDSA_info *info, void *mem,
460 BOOL (WINAPI *pFDSA_Destroy)(FDSA_info *info);
461 DWORD (WINAPI *pFDSA_InsertItem)(FDSA_info *info, DWORD where, const void *block);
462 BOOL (WINAPI *pFDSA_DeleteItem)(FDSA_info *info, DWORD where);
465 int block_size = 10, init_blocks = 4, inc = 2;
469 pFDSA_Initialize = (void *)GetProcAddress(hShlwapi, (LPSTR)208);
470 pFDSA_Destroy = (void *)GetProcAddress(hShlwapi, (LPSTR)209);
471 pFDSA_InsertItem = (void *)GetProcAddress(hShlwapi, (LPSTR)210);
472 pFDSA_DeleteItem = (void *)GetProcAddress(hShlwapi, (LPSTR)211);
474 mem = HeapAlloc(GetProcessHeap(), 0, block_size * init_blocks);
475 memset(&info, 0, sizeof(info));
477 ok(pFDSA_Initialize(block_size, inc, &info, mem, init_blocks), "FDSA_Initialize rets FALSE\n");
478 ok(info.num_items == 0, "num_items = %d\n", info.num_items);
479 ok(info.mem == mem, "mem = %p\n", info.mem);
480 ok(info.blocks_alloced == init_blocks, "blocks_alloced = %d\n", info.blocks_alloced);
481 ok(info.inc == inc, "inc = %d\n", info.inc);
482 ok(info.block_size == block_size, "block_size = %d\n", info.block_size);
483 ok(info.flags == 0, "flags = %d\n", info.flags);
485 ret = pFDSA_InsertItem(&info, 1234, "1234567890");
486 ok(ret == 0, "ret = %d\n", ret);
487 ok(info.num_items == 1, "num_items = %d\n", info.num_items);
488 ok(info.mem == mem, "mem = %p\n", info.mem);
489 ok(info.blocks_alloced == init_blocks, "blocks_alloced = %d\n", info.blocks_alloced);
490 ok(info.inc == inc, "inc = %d\n", info.inc);
491 ok(info.block_size == block_size, "block_size = %d\n", info.block_size);
492 ok(info.flags == 0, "flags = %d\n", info.flags);
494 ret = pFDSA_InsertItem(&info, 1234, "abcdefghij");
495 ok(ret == 1, "ret = %d\n", ret);
497 ret = pFDSA_InsertItem(&info, 1, "klmnopqrst");
498 ok(ret == 1, "ret = %d\n", ret);
500 ret = pFDSA_InsertItem(&info, 0, "uvwxyzABCD");
501 ok(ret == 0, "ret = %d\n", ret);
502 ok(info.mem == mem, "mem = %p\n", info.mem);
503 ok(info.flags == 0, "flags = %d\n", info.flags);
505 /* This next InsertItem will cause shlwapi to allocate its own mem buffer */
506 ret = pFDSA_InsertItem(&info, 0, "EFGHIJKLMN");
507 ok(ret == 0, "ret = %d\n", ret);
508 ok(info.mem != mem, "mem = %p\n", info.mem);
509 ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %d\n", info.blocks_alloced);
510 ok(info.flags == 0x1, "flags = %d\n", info.flags);
512 ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCD1234567890klmnopqrstabcdefghij", 50), "mem %s\n", (char*)info.mem);
514 ok(pFDSA_DeleteItem(&info, 2), "rets FALSE\n");
515 ok(info.mem != mem, "mem = %p\n", info.mem);
516 ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %d\n", info.blocks_alloced);
517 ok(info.flags == 0x1, "flags = %d\n", info.flags);
519 ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCDklmnopqrstabcdefghij", 40), "mem %s\n", (char*)info.mem);
521 ok(pFDSA_DeleteItem(&info, 3), "rets FALSE\n");
522 ok(info.mem != mem, "mem = %p\n", info.mem);
523 ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %d\n", info.blocks_alloced);
524 ok(info.flags == 0x1, "flags = %d\n", info.flags);
526 ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCDklmnopqrst", 30), "mem %s\n", (char*)info.mem);
528 ok(!pFDSA_DeleteItem(&info, 4), "does not ret FALSE\n");
530 /* As shlwapi has allocated memory internally, Destroy will ret FALSE */
531 ok(!pFDSA_Destroy(&info), "FDSA_Destroy does not ret FALSE\n");
534 /* When Initialize is called with inc = 0, set it to 1 */
535 ok(pFDSA_Initialize(block_size, 0, &info, mem, init_blocks), "FDSA_Initialize rets FALSE\n");
536 ok(info.inc == 1, "inc = %d\n", info.inc);
538 /* This time, because shlwapi hasn't had to allocate memory
539 internally, Destroy rets non-zero */
540 ok(pFDSA_Destroy(&info), "FDSA_Destroy rets FALSE\n");
543 HeapFree(GetProcessHeap(), 0, mem);
547 typedef struct SHELL_USER_SID {
548 SID_IDENTIFIER_AUTHORITY sidAuthority;
551 } SHELL_USER_SID, *PSHELL_USER_SID;
552 typedef struct SHELL_USER_PERMISSION {
553 SHELL_USER_SID susID;
558 DWORD dwInheritAccessMask;
559 } SHELL_USER_PERMISSION, *PSHELL_USER_PERMISSION;
560 static void test_GetShellSecurityDescriptor(void)
562 SHELL_USER_PERMISSION supCurrentUserFull = {
563 { {SECURITY_NULL_SID_AUTHORITY}, 0, 0 },
564 ACCESS_ALLOWED_ACE_TYPE, FALSE,
566 #define MY_INHERITANCE 0xBE /* invalid value to proof behavior */
567 SHELL_USER_PERMISSION supEveryoneDenied = {
568 { {SECURITY_WORLD_SID_AUTHORITY}, SECURITY_WORLD_RID, 0 },
569 ACCESS_DENIED_ACE_TYPE, TRUE,
570 GENERIC_WRITE, MY_INHERITANCE | 0xDEADBA00, GENERIC_READ };
571 PSHELL_USER_PERMISSION rgsup[2] = {
572 &supCurrentUserFull, &supEveryoneDenied,
574 SECURITY_DESCRIPTOR* psd;
575 SECURITY_DESCRIPTOR* (WINAPI*pGetShellSecurityDescriptor)(PSHELL_USER_PERMISSION*,int);
577 pGetShellSecurityDescriptor=(void*)GetProcAddress(hShlwapi,(char*)475);
579 if(!pGetShellSecurityDescriptor)
581 win_skip("GetShellSecurityDescriptor not available\n");
585 psd = pGetShellSecurityDescriptor(NULL, 2);
587 broken(psd==INVALID_HANDLE_VALUE), /* IE5 */
588 "GetShellSecurityDescriptor should fail\n");
589 psd = pGetShellSecurityDescriptor(rgsup, 0);
590 ok(psd==NULL, "GetShellSecurityDescriptor should fail\n");
592 SetLastError(0xdeadbeef);
593 psd = pGetShellSecurityDescriptor(rgsup, 2);
594 if (psd == NULL && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
596 /* The previous calls to GetShellSecurityDescriptor don't set the last error */
597 win_skip("GetShellSecurityDescriptor is not implemented\n");
600 if (psd==INVALID_HANDLE_VALUE)
602 win_skip("GetShellSecurityDescriptor is broken on IE5\n");
605 ok(psd!=NULL, "GetShellSecurityDescriptor failed\n");
608 BOOL bHasDacl = FALSE, bDefaulted;
611 SECURITY_DESCRIPTOR_CONTROL control;
613 ok(IsValidSecurityDescriptor(psd), "returned value is not valid SD\n");
615 ok(GetSecurityDescriptorControl(psd, &control, &dwRev),
616 "GetSecurityDescriptorControl failed with error %u\n", GetLastError());
617 ok(0 == (control & SE_SELF_RELATIVE), "SD should be absolute\n");
619 ok(GetSecurityDescriptorDacl(psd, &bHasDacl, &pAcl, &bDefaulted),
620 "GetSecurityDescriptorDacl failed with error %u\n", GetLastError());
622 ok(bHasDacl, "SD has no DACL\n");
625 ok(!bDefaulted, "DACL should not be defaulted\n");
627 ok(pAcl != NULL, "NULL DACL!\n");
630 ACL_SIZE_INFORMATION asiSize;
632 ok(IsValidAcl(pAcl), "DACL is not valid\n");
634 ok(GetAclInformation(pAcl, &asiSize, sizeof(asiSize), AclSizeInformation),
635 "GetAclInformation failed with error %u\n", GetLastError());
637 ok(asiSize.AceCount == 3, "Incorrect number of ACEs: %d entries\n", asiSize.AceCount);
638 if (asiSize.AceCount == 3)
640 ACCESS_ALLOWED_ACE *paaa; /* will use for DENIED too */
642 ok(GetAce(pAcl, 0, (LPVOID*)&paaa), "GetAce failed with error %u\n", GetLastError());
643 ok(paaa->Header.AceType == ACCESS_ALLOWED_ACE_TYPE,
644 "Invalid ACE type %d\n", paaa->Header.AceType);
645 ok(paaa->Header.AceFlags == 0, "Invalid ACE flags %x\n", paaa->Header.AceFlags);
646 ok(paaa->Mask == GENERIC_ALL, "Invalid ACE mask %x\n", paaa->Mask);
648 ok(GetAce(pAcl, 1, (LPVOID*)&paaa), "GetAce failed with error %u\n", GetLastError());
649 ok(paaa->Header.AceType == ACCESS_DENIED_ACE_TYPE,
650 "Invalid ACE type %d\n", paaa->Header.AceType);
651 /* first one of two ACEs generated from inheritable entry - without inheritance */
652 ok(paaa->Header.AceFlags == 0, "Invalid ACE flags %x\n", paaa->Header.AceFlags);
653 ok(paaa->Mask == GENERIC_WRITE, "Invalid ACE mask %x\n", paaa->Mask);
655 ok(GetAce(pAcl, 2, (LPVOID*)&paaa), "GetAce failed with error %u\n", GetLastError());
656 ok(paaa->Header.AceType == ACCESS_DENIED_ACE_TYPE,
657 "Invalid ACE type %d\n", paaa->Header.AceType);
658 /* second ACE - with inheritance */
659 ok(paaa->Header.AceFlags == MY_INHERITANCE,
660 "Invalid ACE flags %x\n", paaa->Header.AceFlags);
661 ok(paaa->Mask == GENERIC_READ, "Invalid ACE mask %x\n", paaa->Mask);
670 static void test_SHPackDispParams(void)
676 if(!pSHPackDispParams)
677 win_skip("SHPackSidpParams not available\n");
679 memset(¶ms, 0xc0, sizeof(params));
680 memset(vars, 0xc0, sizeof(vars));
681 hres = pSHPackDispParams(¶ms, vars, 1, VT_I4, 0xdeadbeef);
682 ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres);
683 ok(params.cArgs == 1, "params.cArgs = %d\n", params.cArgs);
684 ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
685 ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
686 ok(params.rgvarg == vars, "params.rgvarg = %p\n", params.rgvarg);
687 ok(V_VT(vars) == VT_I4, "V_VT(var) = %d\n", V_VT(vars));
688 ok(V_I4(vars) == 0xdeadbeef, "failed %x\n", V_I4(vars));
690 memset(¶ms, 0xc0, sizeof(params));
691 hres = pSHPackDispParams(¶ms, NULL, 0, 0);
692 ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres);
693 ok(params.cArgs == 0, "params.cArgs = %d\n", params.cArgs);
694 ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
695 ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
696 ok(params.rgvarg == NULL, "params.rgvarg = %p\n", params.rgvarg);
698 memset(vars, 0xc0, sizeof(vars));
699 memset(¶ms, 0xc0, sizeof(params));
700 hres = pSHPackDispParams(¶ms, vars, 4, VT_BSTR, (void*)0xdeadbeef, VT_EMPTY, 10,
701 VT_I4, 100, VT_DISPATCH, (void*)0xdeadbeef);
702 ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres);
703 ok(params.cArgs == 4, "params.cArgs = %d\n", params.cArgs);
704 ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
705 ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
706 ok(params.rgvarg == vars, "params.rgvarg = %p\n", params.rgvarg);
707 ok(V_VT(vars) == VT_DISPATCH, "V_VT(vars[0]) = %x\n", V_VT(vars));
708 ok(V_I4(vars) == 0xdeadbeef, "V_I4(vars[0]) = %x\n", V_I4(vars));
709 ok(V_VT(vars+1) == VT_I4, "V_VT(vars[1]) = %d\n", V_VT(vars+1));
710 ok(V_I4(vars+1) == 100, "V_I4(vars[1]) = %x\n", V_I4(vars+1));
711 ok(V_VT(vars+2) == VT_I4, "V_VT(vars[2]) = %d\n", V_VT(vars+2));
712 ok(V_I4(vars+2) == 10, "V_I4(vars[2]) = %x\n", V_I4(vars+2));
713 ok(V_VT(vars+3) == VT_BSTR, "V_VT(vars[3]) = %d\n", V_VT(vars+3));
714 ok(V_BSTR(vars+3) == (void*)0xdeadbeef, "V_BSTR(vars[3]) = %p\n", V_BSTR(vars+3));
719 const IDispatchVtbl *vtbl;
723 typedef struct _contain
725 const IConnectionPointContainerVtbl *vtbl;
729 IConnectionPoint **pt;
732 typedef struct _cntptn
734 const IConnectionPointVtbl *vtbl;
745 const IEnumConnectionsVtbl *vtbl;
752 typedef struct _enumpt
754 const IEnumConnectionPointsVtbl *vtbl;
762 static HRESULT WINAPI Disp_QueryInterface(
769 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDispatch))
776 IUnknown_AddRef(This);
780 trace("no interface\n");
781 return E_NOINTERFACE;
784 static ULONG WINAPI Disp_AddRef(IDispatch* This)
786 Disp *iface = (Disp*)This;
787 return InterlockedIncrement(&iface->refCount);
790 static ULONG WINAPI Disp_Release(IDispatch* This)
792 Disp *iface = (Disp*)This;
795 ret = InterlockedDecrement(&iface->refCount);
797 HeapFree(GetProcessHeap(),0,This);
801 static HRESULT WINAPI Disp_GetTypeInfoCount(
805 return ERROR_SUCCESS;
808 static HRESULT WINAPI Disp_GetTypeInfo(
814 return ERROR_SUCCESS;
817 static HRESULT WINAPI Disp_GetIDsOfNames(
825 return ERROR_SUCCESS;
828 static HRESULT WINAPI Disp_Invoke(
834 DISPPARAMS *pDispParams,
836 EXCEPINFO *pExcepInfo,
839 trace("%p %x %p %x %x %p %p %p %p\n",This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
841 ok(dispIdMember == 0xa0 || dispIdMember == 0xa1, "Unknown dispIdMember\n");
842 ok(pDispParams != NULL, "Invoked with NULL pDispParams\n");
843 ok(wFlags == DISPATCH_METHOD, "Wrong flags %x\n",wFlags);
844 ok(lcid == 0,"Wrong lcid %x\n",lcid);
845 if (dispIdMember == 0xa0)
847 ok(pDispParams->cArgs == 0, "params.cArgs = %d\n", pDispParams->cArgs);
848 ok(pDispParams->cNamedArgs == 0, "params.cNamedArgs = %d\n", pDispParams->cArgs);
849 ok(pDispParams->rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", pDispParams->rgdispidNamedArgs);
850 ok(pDispParams->rgvarg == NULL, "params.rgvarg = %p\n", pDispParams->rgvarg);
852 else if (dispIdMember == 0xa1)
854 ok(pDispParams->cArgs == 2, "params.cArgs = %d\n", pDispParams->cArgs);
855 ok(pDispParams->cNamedArgs == 0, "params.cNamedArgs = %d\n", pDispParams->cArgs);
856 ok(pDispParams->rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", pDispParams->rgdispidNamedArgs);
857 ok(V_VT(pDispParams->rgvarg) == VT_BSTR, "V_VT(var) = %d\n", V_VT(pDispParams->rgvarg));
858 ok(V_I4(pDispParams->rgvarg) == 0xdeadcafe , "failed %p\n", V_BSTR(pDispParams->rgvarg));
859 ok(V_VT(pDispParams->rgvarg+1) == VT_I4, "V_VT(var) = %d\n", V_VT(pDispParams->rgvarg+1));
860 ok(V_I4(pDispParams->rgvarg+1) == 0xdeadbeef, "failed %x\n", V_I4(pDispParams->rgvarg+1));
863 return ERROR_SUCCESS;
866 static const IDispatchVtbl disp_vtbl = {
871 Disp_GetTypeInfoCount,
877 static HRESULT WINAPI Enum_QueryInterface(
878 IEnumConnections* This,
884 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumConnections))
891 IUnknown_AddRef(This);
895 trace("no interface\n");
896 return E_NOINTERFACE;
899 static ULONG WINAPI Enum_AddRef(IEnumConnections* This)
901 EnumCon *iface = (EnumCon*)This;
902 return InterlockedIncrement(&iface->refCount);
905 static ULONG WINAPI Enum_Release(IEnumConnections* This)
907 EnumCon *iface = (EnumCon*)This;
910 ret = InterlockedDecrement(&iface->refCount);
912 HeapFree(GetProcessHeap(),0,This);
916 static HRESULT WINAPI Enum_Next(
917 IEnumConnections* This,
922 EnumCon *iface = (EnumCon*)This;
924 if (cConnections > 0 && iface->idx < iface->pt->sinkCount)
926 rgcd->pUnk = iface->pt->sink[iface->idx];
927 IUnknown_AddRef(iface->pt->sink[iface->idx]);
938 static HRESULT WINAPI Enum_Skip(
939 IEnumConnections* This,
945 static HRESULT WINAPI Enum_Reset(
946 IEnumConnections* This)
951 static HRESULT WINAPI Enum_Clone(
952 IEnumConnections* This,
953 IEnumConnections **ppEnum)
958 static const IEnumConnectionsVtbl enum_vtbl = {
969 static HRESULT WINAPI ConPt_QueryInterface(
970 IConnectionPoint* This,
976 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IConnectionPoint))
983 IUnknown_AddRef(This);
987 trace("no interface\n");
988 return E_NOINTERFACE;
991 static ULONG WINAPI ConPt_AddRef(
992 IConnectionPoint* This)
994 ConPt *iface = (ConPt*)This;
995 return InterlockedIncrement(&iface->refCount);
998 static ULONG WINAPI ConPt_Release(
999 IConnectionPoint* This)
1001 ConPt *iface = (ConPt*)This;
1004 ret = InterlockedDecrement(&iface->refCount);
1007 if (iface->sinkCount > 0)
1010 for (i = 0; i < iface->sinkCount; i++)
1013 IUnknown_Release(iface->sink[i]);
1015 HeapFree(GetProcessHeap(),0,iface->sink);
1017 HeapFree(GetProcessHeap(),0,This);
1022 static HRESULT WINAPI ConPt_GetConnectionInterface(
1023 IConnectionPoint* This,
1027 ConPt *iface = (ConPt*)This;
1034 memcpy(pIID,&iface->id,sizeof(GUID));
1038 static HRESULT WINAPI ConPt_GetConnectionPointContainer(
1039 IConnectionPoint* This,
1040 IConnectionPointContainer **ppCPC)
1042 ConPt *iface = (ConPt*)This;
1044 *ppCPC = (IConnectionPointContainer*)iface->container;
1048 static HRESULT WINAPI ConPt_Advise(
1049 IConnectionPoint* This,
1053 ConPt *iface = (ConPt*)This;
1055 if (iface->sinkCount == 0)
1056 iface->sink = HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown*));
1058 iface->sink = HeapReAlloc(GetProcessHeap(),0,iface->sink,sizeof(IUnknown*)*(iface->sinkCount+1));
1059 iface->sink[iface->sinkCount] = pUnkSink;
1060 IUnknown_AddRef(pUnkSink);
1062 *pdwCookie = iface->sinkCount;
1066 static HRESULT WINAPI ConPt_Unadvise(
1067 IConnectionPoint* This,
1070 ConPt *iface = (ConPt*)This;
1072 if (dwCookie > iface->sinkCount)
1076 IUnknown_Release(iface->sink[dwCookie-1]);
1077 iface->sink[dwCookie-1] = NULL;
1082 static HRESULT WINAPI ConPt_EnumConnections(
1083 IConnectionPoint* This,
1084 IEnumConnections **ppEnum)
1088 ec = HeapAlloc(GetProcessHeap(),0,sizeof(EnumCon));
1089 ec->vtbl = &enum_vtbl;
1091 ec->pt = (ConPt*)This;
1093 *ppEnum = (IEnumConnections*)ec;
1098 static const IConnectionPointVtbl point_vtbl = {
1099 ConPt_QueryInterface,
1103 ConPt_GetConnectionInterface,
1104 ConPt_GetConnectionPointContainer,
1107 ConPt_EnumConnections
1110 static HRESULT WINAPI EnumPt_QueryInterface(
1111 IEnumConnectionPoints* This,
1117 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumConnectionPoints))
1124 IUnknown_AddRef(This);
1128 trace("no interface\n");
1129 return E_NOINTERFACE;
1132 static ULONG WINAPI EnumPt_AddRef(IEnumConnectionPoints* This)
1134 EnumPt *iface = (EnumPt*)This;
1135 return InterlockedIncrement(&iface->refCount);
1138 static ULONG WINAPI EnumPt_Release(IEnumConnectionPoints* This)
1140 EnumPt *iface = (EnumPt*)This;
1143 ret = InterlockedDecrement(&iface->refCount);
1145 HeapFree(GetProcessHeap(),0,This);
1149 static HRESULT WINAPI EnumPt_Next(
1150 IEnumConnectionPoints* This,
1152 IConnectionPoint **rgcd,
1155 EnumPt *iface = (EnumPt*)This;
1157 if (cConnections > 0 && iface->idx < iface->container->ptCount)
1159 *rgcd = iface->container->pt[iface->idx];
1160 IUnknown_AddRef(iface->container->pt[iface->idx]);
1170 static HRESULT WINAPI EnumPt_Skip(
1171 IEnumConnectionPoints* This,
1177 static HRESULT WINAPI EnumPt_Reset(
1178 IEnumConnectionPoints* This)
1183 static HRESULT WINAPI EnumPt_Clone(
1184 IEnumConnectionPoints* This,
1185 IEnumConnectionPoints **ppEnumPt)
1190 static const IEnumConnectionPointsVtbl enumpt_vtbl = {
1192 EnumPt_QueryInterface,
1201 static HRESULT WINAPI Contain_QueryInterface(
1202 IConnectionPointContainer* This,
1208 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IConnectionPointContainer))
1215 IUnknown_AddRef(This);
1219 trace("no interface\n");
1220 return E_NOINTERFACE;
1223 static ULONG WINAPI Contain_AddRef(
1224 IConnectionPointContainer* This)
1226 Contain *iface = (Contain*)This;
1227 return InterlockedIncrement(&iface->refCount);
1230 static ULONG WINAPI Contain_Release(
1231 IConnectionPointContainer* This)
1233 Contain *iface = (Contain*)This;
1236 ret = InterlockedDecrement(&iface->refCount);
1239 if (iface->ptCount > 0)
1242 for (i = 0; i < iface->ptCount; i++)
1243 IUnknown_Release(iface->pt[i]);
1244 HeapFree(GetProcessHeap(),0,iface->pt);
1246 HeapFree(GetProcessHeap(),0,This);
1251 static HRESULT WINAPI Contain_EnumConnectionPoints(
1252 IConnectionPointContainer* This,
1253 IEnumConnectionPoints **ppEnum)
1257 ec = HeapAlloc(GetProcessHeap(),0,sizeof(EnumPt));
1258 ec->vtbl = &enumpt_vtbl;
1261 ec->container = (Contain*)This;
1262 *ppEnum = (IEnumConnectionPoints*)ec;
1267 static HRESULT WINAPI Contain_FindConnectionPoint(
1268 IConnectionPointContainer* This,
1270 IConnectionPoint **ppCP)
1272 Contain *iface = (Contain*)This;
1275 if (!IsEqualIID(riid, &IID_NULL) || iface->ptCount ==0)
1277 pt = HeapAlloc(GetProcessHeap(),0,sizeof(ConPt));
1278 pt->vtbl = &point_vtbl;
1282 pt->container = iface;
1283 pt->id = IID_IDispatch;
1285 if (iface->ptCount == 0)
1286 iface->pt =HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown*));
1288 iface->pt = HeapReAlloc(GetProcessHeap(),0,iface->pt,sizeof(IUnknown*)*(iface->ptCount+1));
1289 iface->pt[iface->ptCount] = (IConnectionPoint*)pt;
1292 *ppCP = (IConnectionPoint*)pt;
1296 *ppCP = iface->pt[0];
1297 IUnknown_AddRef((IUnknown*)*ppCP);
1303 static const IConnectionPointContainerVtbl contain_vtbl = {
1304 Contain_QueryInterface,
1308 Contain_EnumConnectionPoints,
1309 Contain_FindConnectionPoint
1312 static void test_IConnectionPoint(void)
1316 IConnectionPoint *point;
1319 DWORD cookie = 0xffffffff;
1323 if (!pIConnectionPoint_SimpleInvoke || !pConnectToConnectionPoint)
1325 win_skip("IConnectionPoint Apis not present\n");
1329 container = HeapAlloc(GetProcessHeap(),0,sizeof(Contain));
1330 container->vtbl = &contain_vtbl;
1331 container->refCount = 1;
1332 container->ptCount = 0;
1333 container->pt = NULL;
1335 dispatch = HeapAlloc(GetProcessHeap(),0,sizeof(Disp));
1336 dispatch->vtbl = &disp_vtbl;
1337 dispatch->refCount = 1;
1339 rc = pConnectToConnectionPoint((IUnknown*)dispatch, &IID_NULL, TRUE, (IUnknown*)container, &cookie, &point);
1340 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1341 ok(point != NULL, "returned ConnectionPoint is NULL\n");
1342 ok(cookie != 0xffffffff, "invalid cookie returned\n");
1344 rc = pIConnectionPoint_SimpleInvoke(point,0xa0,NULL);
1345 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1347 if (pSHPackDispParams)
1349 memset(¶ms, 0xc0, sizeof(params));
1350 memset(vars, 0xc0, sizeof(vars));
1351 rc = pSHPackDispParams(¶ms, vars, 2, VT_I4, 0xdeadbeef, VT_BSTR, 0xdeadcafe);
1352 ok(rc == S_OK, "SHPackDispParams failed: %08x\n", rc);
1354 rc = pIConnectionPoint_SimpleInvoke(point,0xa1,¶ms);
1355 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1358 win_skip("pSHPackDispParams not present\n");
1360 rc = pConnectToConnectionPoint(NULL, &IID_NULL, FALSE, (IUnknown*)container, &cookie, NULL);
1361 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1363 /* MSDN says this should be required but it crashs on XP
1364 IUnknown_Release(point);
1366 ref = IUnknown_Release((IUnknown*)container);
1367 ok(ref == 0, "leftover IConnectionPointContainer reference %i\n",ref);
1368 ref = IUnknown_Release((IUnknown*)dispatch);
1369 ok(ref == 0, "leftover IDispatch reference %i\n",ref);
1372 typedef struct _propbag
1374 const IPropertyBagVtbl *vtbl;
1380 static HRESULT WINAPI Prop_QueryInterface(
1387 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPropertyBag))
1394 IUnknown_AddRef(This);
1398 trace("no interface\n");
1399 return E_NOINTERFACE;
1402 static ULONG WINAPI Prop_AddRef(
1405 PropBag *iface = (PropBag*)This;
1406 return InterlockedIncrement(&iface->refCount);
1409 static ULONG WINAPI Prop_Release(
1412 PropBag *iface = (PropBag*)This;
1415 ret = InterlockedDecrement(&iface->refCount);
1417 HeapFree(GetProcessHeap(),0,This);
1421 static HRESULT WINAPI Prop_Read(
1423 LPCOLESTR pszPropName,
1425 IErrorLog *pErrorLog)
1427 V_VT(pVar) = VT_BLOB|VT_BYREF;
1428 V_BYREF(pVar) = (LPVOID)0xdeadcafe;
1432 static HRESULT WINAPI Prop_Write(
1434 LPCOLESTR pszPropName,
1441 static const IPropertyBagVtbl prop_vtbl = {
1442 Prop_QueryInterface,
1450 static void test_SHPropertyBag_ReadLONG(void)
1455 static const WCHAR szName1[] = {'n','a','m','e','1',0};
1457 if (!pSHPropertyBag_ReadLONG)
1459 win_skip("SHPropertyBag_ReadLONG not present\n");
1463 pb = HeapAlloc(GetProcessHeap(),0,sizeof(PropBag));
1465 pb->vtbl = &prop_vtbl;
1468 rc = pSHPropertyBag_ReadLONG(NULL, szName1, &out);
1469 ok(rc == E_INVALIDARG || broken(rc == 0), "incorrect return %x\n",rc);
1470 ok(out == 0xfeedface, "value should not have changed\n");
1471 rc = pSHPropertyBag_ReadLONG((IPropertyBag*)pb, NULL, &out);
1472 ok(rc == E_INVALIDARG || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
1473 ok(out == 0xfeedface, "value should not have changed\n");
1474 rc = pSHPropertyBag_ReadLONG((IPropertyBag*)pb, szName1, NULL);
1475 ok(rc == E_INVALIDARG || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
1476 ok(out == 0xfeedface, "value should not have changed\n");
1477 rc = pSHPropertyBag_ReadLONG((IPropertyBag*)pb, szName1, &out);
1478 ok(rc == DISP_E_BADVARTYPE || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
1479 ok(out == 0xfeedface || broken(out == 0xfeedfa00), "value should not have changed %x\n",out);
1480 IUnknown_Release((IUnknown*)pb);
1485 static void test_SHSetWindowBits(void)
1488 DWORD style, styleold;
1491 if(!pSHSetWindowBits)
1493 win_skip("SHSetWindowBits is not available\n");
1498 clsA.lpfnWndProc = DefWindowProcA;
1499 clsA.cbClsExtra = 0;
1500 clsA.cbWndExtra = 0;
1501 clsA.hInstance = GetModuleHandleA(NULL);
1503 clsA.hCursor = LoadCursorA(0, IDC_ARROW);
1504 clsA.hbrBackground = NULL;
1505 clsA.lpszMenuName = NULL;
1506 clsA.lpszClassName = "Shlwapi test class";
1507 RegisterClassA(&clsA);
1509 hwnd = CreateWindowA("Shlwapi test class", "Test", WS_VISIBLE, 0, 0, 100, 100,
1510 NULL, NULL, GetModuleHandle(NULL), 0);
1511 ok(IsWindow(hwnd), "failed to create window\n");
1514 SetLastError(0xdeadbeef);
1515 style = pSHSetWindowBits(NULL, GWL_STYLE, 0, 0);
1516 ok(style == 0, "expected 0 retval, got %d\n", style);
1517 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
1518 broken(GetLastError() == 0xdeadbeef), /* Win9x/WinMe */
1519 "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
1521 /* zero mask, zero flags */
1522 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1523 style = pSHSetWindowBits(hwnd, GWL_STYLE, 0, 0);
1524 ok(styleold == style, "expected old style\n");
1525 ok(styleold == GetWindowLongA(hwnd, GWL_STYLE), "expected to keep old style\n");
1528 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1529 ok(styleold & WS_VISIBLE, "expected WS_VISIBLE\n");
1530 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1532 ok(style == styleold, "expected previous style, got %x\n", style);
1533 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1535 /* test mask, unset style bit used */
1536 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1537 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1538 ok(style == styleold, "expected previous style, got %x\n", style);
1539 ok(styleold == GetWindowLongA(hwnd, GWL_STYLE), "expected to keep old style\n");
1541 /* set back with flags */
1542 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1543 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, WS_VISIBLE);
1544 ok(style == styleold, "expected previous style, got %x\n", style);
1545 ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "expected updated style\n");
1547 /* reset and try to set without a mask */
1548 pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1549 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1550 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1551 style = pSHSetWindowBits(hwnd, GWL_STYLE, 0, WS_VISIBLE);
1552 ok(style == styleold, "expected previous style, got %x\n", style);
1553 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1555 DestroyWindow(hwnd);
1557 UnregisterClassA("Shlwapi test class", GetModuleHandleA(NULL));
1560 static void test_SHFormatDateTimeA(void)
1562 FILETIME UNALIGNED filetime;
1563 CHAR buff[100], buff2[100], buff3[100];
1568 if(!pSHFormatDateTimeA)
1570 win_skip("pSHFormatDateTimeA isn't available\n");
1576 /* crashes on native */
1577 ret = pSHFormatDateTimeA(NULL, NULL, NULL, 0);
1581 SystemTimeToFileTime(&st, &filetime);
1582 /* SHFormatDateTime expects input as utc */
1583 LocalFileTimeToFileTime(&filetime, &filetime);
1585 /* no way to get required buffer length here */
1586 SetLastError(0xdeadbeef);
1587 ret = pSHFormatDateTimeA(&filetime, NULL, NULL, 0);
1588 ok(ret == 0, "got %d\n", ret);
1589 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1591 SetLastError(0xdeadbeef);
1592 buff[0] = 'a'; buff[1] = 0;
1593 ret = pSHFormatDateTimeA(&filetime, NULL, buff, 0);
1594 ok(ret == 0, "got %d\n", ret);
1595 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1596 ok(buff[0] == 'a', "expected same string, got %s\n", buff);
1598 /* flags needs to have FDTF_NOAUTOREADINGORDER for these tests to succeed on Vista+ */
1600 /* all combinations documented as invalid succeeded */
1601 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTTIME | FDTF_LONGTIME;
1602 SetLastError(0xdeadbeef);
1603 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1604 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1605 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1607 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_LONGDATE;
1608 SetLastError(0xdeadbeef);
1609 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1610 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1611 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1613 flags = FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE;
1614 SetLastError(0xdeadbeef);
1615 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1616 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1617 ok(GetLastError() == 0xdeadbeef ||
1618 broken(GetLastError() == ERROR_INVALID_FLAGS), /* Win9x/WinMe */
1619 "expected 0xdeadbeef, got %d\n", GetLastError());
1621 /* now check returned strings */
1622 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTTIME;
1623 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1624 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1625 ret = GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff2, sizeof(buff2));
1626 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1627 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1629 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGTIME;
1630 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1631 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1632 ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2));
1633 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1634 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1636 /* both time flags */
1637 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGTIME | FDTF_SHORTTIME;
1638 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1639 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1640 ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2));
1641 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1642 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1644 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE;
1645 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1646 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1647 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1648 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1649 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1651 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE;
1652 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1653 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1654 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1655 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1656 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1658 /* both date flags */
1659 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_SHORTDATE;
1660 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1661 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1662 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1663 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1664 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1666 /* various combinations of date/time flags */
1667 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_SHORTTIME;
1668 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1669 ok(ret == lstrlenA(buff)+1, "got %d, length %d\n", ret, lstrlenA(buff)+1);
1670 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1671 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1672 strcat(buff2, ", ");
1673 ret = GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3));
1674 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1675 strcat(buff2, buff3);
1676 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1678 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_LONGTIME;
1679 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1680 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1681 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1682 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1683 strcat(buff2, ", ");
1684 ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3));
1685 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1686 strcat(buff2, buff3);
1687 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1689 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_SHORTTIME;
1690 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1691 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1692 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1693 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1695 ret = GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3));
1696 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1697 strcat(buff2, buff3);
1698 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1700 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_LONGTIME;
1701 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1702 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1703 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1704 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1706 ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3));
1707 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1708 strcat(buff2, buff3);
1709 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1712 static void test_SHFormatDateTimeW(void)
1714 FILETIME UNALIGNED filetime;
1715 WCHAR buff[100], buff2[100], buff3[100];
1719 static const WCHAR spaceW[] = {' ',0};
1720 static const WCHAR commaW[] = {',',' ',0};
1722 if(!pSHFormatDateTimeW)
1724 win_skip("pSHFormatDateTimeW isn't available\n");
1730 /* crashes on native */
1731 ret = pSHFormatDateTimeW(NULL, NULL, NULL, 0);
1735 SystemTimeToFileTime(&st, &filetime);
1736 /* SHFormatDateTime expects input as utc */
1737 LocalFileTimeToFileTime(&filetime, &filetime);
1739 /* no way to get required buffer length here */
1740 SetLastError(0xdeadbeef);
1741 ret = pSHFormatDateTimeW(&filetime, NULL, NULL, 0);
1742 ok(ret == 0, "got %d\n", ret);
1743 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1745 SetLastError(0xdeadbeef);
1746 buff[0] = 'a'; buff[1] = 0;
1747 ret = pSHFormatDateTimeW(&filetime, NULL, buff, 0);
1748 ok(ret == 0, "got %d\n", ret);
1749 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1750 ok(buff[0] == 'a', "expected same string\n");
1752 /* all combinations documented as invalid succeeded */
1753 flags = FDTF_SHORTTIME | FDTF_LONGTIME;
1754 SetLastError(0xdeadbeef);
1755 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1756 ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
1757 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1759 flags = FDTF_SHORTDATE | FDTF_LONGDATE;
1760 SetLastError(0xdeadbeef);
1761 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1762 ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
1763 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1765 flags = FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE;
1766 SetLastError(0xdeadbeef);
1767 buff[0] = 0; /* NT4 doesn't clear the buffer on failure */
1768 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1769 ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
1770 ok(GetLastError() == 0xdeadbeef ||
1771 broken(GetLastError() == ERROR_INVALID_FLAGS), /* Win9x/WinMe/NT4 */
1772 "expected 0xdeadbeef, got %d\n", GetLastError());
1774 /* now check returned strings */
1775 flags = FDTF_SHORTTIME;
1776 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1777 ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
1778 SetLastError(0xdeadbeef);
1779 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1780 if (ret == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1782 win_skip("Needed W-functions are not implemented\n");
1785 ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
1786 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1788 flags = FDTF_LONGTIME;
1789 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1790 ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
1791 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1792 ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
1793 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1795 /* both time flags */
1796 flags = FDTF_LONGTIME | FDTF_SHORTTIME;
1797 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1798 ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
1799 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1800 ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
1801 ok(lstrcmpW(buff, buff2) == 0, "expected equal string\n");
1803 flags = FDTF_SHORTDATE;
1804 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1805 ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
1806 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1807 ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
1808 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1810 flags = FDTF_LONGDATE;
1811 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1812 ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
1813 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1814 ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
1815 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1817 /* both date flags */
1818 flags = FDTF_LONGDATE | FDTF_SHORTDATE;
1819 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1820 ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
1821 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1822 ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
1823 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1825 /* various combinations of date/time flags */
1826 flags = FDTF_LONGDATE | FDTF_SHORTTIME;
1827 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1828 ok(ret == lstrlenW(buff)+1, "got %d, length %d\n", ret, lstrlenW(buff)+1);
1829 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1830 ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
1831 lstrcatW(buff2, commaW);
1832 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1833 ok(ret == lstrlenW(buff3)+1, "got %d\n", ret);
1834 lstrcatW(buff2, buff3);
1835 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1837 flags = FDTF_LONGDATE | FDTF_LONGTIME;
1838 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1839 ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
1840 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1841 ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
1842 lstrcatW(buff2, commaW);
1843 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1844 ok(ret == lstrlenW(buff3)+1, "got %d\n", ret);
1845 lstrcatW(buff2, buff3);
1846 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1848 flags = FDTF_SHORTDATE | FDTF_SHORTTIME;
1849 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1850 ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
1851 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1852 ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
1853 lstrcatW(buff2, spaceW);
1854 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1855 ok(ret == lstrlenW(buff3)+1, "got %d\n", ret);
1856 lstrcatW(buff2, buff3);
1857 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1859 flags = FDTF_SHORTDATE | FDTF_LONGTIME;
1860 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1861 ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
1862 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1863 ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
1864 lstrcatW(buff2, spaceW);
1865 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1866 ok(ret == lstrlenW(buff3)+1, "got %d\n", ret);
1867 lstrcatW(buff2, buff3);
1868 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1871 static void test_SHGetObjectCompatFlags(void)
1873 struct compat_value {
1878 struct compat_value values[] = {
1879 { "OTNEEDSSFCACHE", 0x1 },
1880 { "NO_WEBVIEW", 0x2 },
1881 { "UNBINDABLE", 0x4 },
1883 { "NEEDSFILESYSANCESTOR", 0x10 },
1884 { "NOTAFILESYSTEM", 0x20 },
1885 { "CTXMENU_NOVERBS", 0x40 },
1886 { "CTXMENU_LIMITEDQI", 0x80 },
1887 { "COCREATESHELLFOLDERONLY", 0x100 },
1888 { "NEEDSSTORAGEANCESTOR", 0x200 },
1889 { "NOLEGACYWEBVIEW", 0x400 },
1890 { "CTXMENU_XPQCMFLAGS", 0x1000 },
1891 { "NOIPROPERTYSTORE", 0x2000 }
1894 static const char compat_path[] = "Software\\Microsoft\\Windows\\CurrentVersion\\ShellCompatibility\\Objects";
1895 CHAR keyA[39]; /* {CLSID} */
1900 if (!pSHGetObjectCompatFlags)
1902 win_skip("SHGetObjectCompatFlags isn't available\n");
1907 ret = pSHGetObjectCompatFlags(NULL, NULL);
1908 ok(ret == 0, "got %d\n", ret);
1910 ret = RegOpenKeyA(HKEY_LOCAL_MACHINE, compat_path, &root);
1911 if (ret != ERROR_SUCCESS)
1913 skip("No compatibility class data found\n");
1917 for (i = 0; RegEnumKeyA(root, i, keyA, sizeof(keyA)) == ERROR_SUCCESS; i++)
1921 if (RegOpenKeyA(root, keyA, &clsid_key) == ERROR_SUCCESS)
1924 DWORD expected = 0, got, length = sizeof(valueA);
1928 for (v = 0; RegEnumValueA(clsid_key, v, valueA, &length, NULL, NULL, NULL, NULL) == ERROR_SUCCESS; v++)
1932 for (j = 0; j < sizeof(values)/sizeof(struct compat_value); j++)
1933 if (lstrcmpA(values[j].nameA, valueA) == 0)
1935 expected |= values[j].value;
1939 length = sizeof(valueA);
1942 pGUIDFromStringA(keyA, &clsid);
1943 got = pSHGetObjectCompatFlags(NULL, &clsid);
1944 ok(got == expected, "got 0x%08x, expected 0x%08x. Key %s\n", got, expected, keyA);
1946 RegCloseKey(clsid_key);
1954 const IOleCommandTargetVtbl *lpVtbl;
1956 } IOleCommandTargetImpl;
1958 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl;
1960 IOleCommandTarget* IOleCommandTargetImpl_Construct(void)
1962 IOleCommandTargetImpl *obj;
1964 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
1965 obj->lpVtbl = &IOleCommandTargetImpl_Vtbl;
1968 return (IOleCommandTarget*)obj;
1971 static HRESULT WINAPI IOleCommandTargetImpl_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppvObj)
1973 IOleCommandTargetImpl *This = (IOleCommandTargetImpl *)iface;
1975 if (IsEqualIID(riid, &IID_IUnknown) ||
1976 IsEqualIID(riid, &IID_IOleCommandTarget))
1983 IUnknown_AddRef(iface);
1987 return E_NOINTERFACE;
1990 static ULONG WINAPI IOleCommandTargetImpl_AddRef(IOleCommandTarget *iface)
1992 IOleCommandTargetImpl *This = (IOleCommandTargetImpl *)iface;
1993 return InterlockedIncrement(&This->ref);
1996 static ULONG WINAPI IOleCommandTargetImpl_Release(IOleCommandTarget *iface)
1998 IOleCommandTargetImpl *This = (IOleCommandTargetImpl *)iface;
1999 ULONG ref = InterlockedDecrement(&This->ref);
2003 HeapFree(GetProcessHeap(), 0, This);
2009 static HRESULT WINAPI IOleCommandTargetImpl_QueryStatus(
2010 IOleCommandTarget *iface, const GUID *group, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText)
2015 static HRESULT WINAPI IOleCommandTargetImpl_Exec(
2016 IOleCommandTarget *iface,
2017 const GUID *CmdGroup,
2023 add_call(&trace_got, 3, CmdGroup, (void*)nCmdID, (void*)nCmdexecopt, pvaIn, pvaOut);
2027 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl =
2029 IOleCommandTargetImpl_QueryInterface,
2030 IOleCommandTargetImpl_AddRef,
2031 IOleCommandTargetImpl_Release,
2032 IOleCommandTargetImpl_QueryStatus,
2033 IOleCommandTargetImpl_Exec
2037 const IServiceProviderVtbl *lpVtbl;
2039 } IServiceProviderImpl;
2042 const IProfferServiceVtbl *lpVtbl;
2044 } IProfferServiceImpl;
2047 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl;
2048 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl;
2050 IServiceProvider* IServiceProviderImpl_Construct(void)
2052 IServiceProviderImpl *obj;
2054 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2055 obj->lpVtbl = &IServiceProviderImpl_Vtbl;
2058 return (IServiceProvider*)obj;
2061 IProfferService* IProfferServiceImpl_Construct(void)
2063 IProfferServiceImpl *obj;
2065 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2066 obj->lpVtbl = &IProfferServiceImpl_Vtbl;
2069 return (IProfferService*)obj;
2072 static HRESULT WINAPI IServiceProviderImpl_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppvObj)
2074 IServiceProviderImpl *This = (IServiceProviderImpl *)iface;
2076 if (IsEqualIID(riid, &IID_IUnknown) ||
2077 IsEqualIID(riid, &IID_IServiceProvider))
2084 IUnknown_AddRef(iface);
2085 /* native uses redefined IID_IServiceProvider symbol, so we can't compare pointers */
2086 if (IsEqualIID(riid, &IID_IServiceProvider))
2087 add_call(&trace_got, 1, iface, &IID_IServiceProvider, 0, 0, 0);
2091 return E_NOINTERFACE;
2094 static ULONG WINAPI IServiceProviderImpl_AddRef(IServiceProvider *iface)
2096 IServiceProviderImpl *This = (IServiceProviderImpl *)iface;
2097 return InterlockedIncrement(&This->ref);
2100 static ULONG WINAPI IServiceProviderImpl_Release(IServiceProvider *iface)
2102 IServiceProviderImpl *This = (IServiceProviderImpl *)iface;
2103 ULONG ref = InterlockedDecrement(&This->ref);
2107 HeapFree(GetProcessHeap(), 0, This);
2113 static HRESULT WINAPI IServiceProviderImpl_QueryService(
2114 IServiceProvider *iface, REFGUID service, REFIID riid, void **ppv)
2116 /* native uses redefined pointer for IID_IOleCommandTarget, not one from uuid.lib */
2117 if (IsEqualIID(riid, &IID_IOleCommandTarget))
2119 add_call(&trace_got, 2, iface, service, &IID_IOleCommandTarget, 0, 0);
2120 *ppv = IOleCommandTargetImpl_Construct();
2122 if (IsEqualIID(riid, &IID_IProfferService))
2124 if (IsEqualIID(service, &IID_IProfferService))
2125 add_call(&trace_got, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2126 *ppv = IProfferServiceImpl_Construct();
2131 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl =
2133 IServiceProviderImpl_QueryInterface,
2134 IServiceProviderImpl_AddRef,
2135 IServiceProviderImpl_Release,
2136 IServiceProviderImpl_QueryService
2139 static void test_IUnknown_QueryServiceExec(void)
2141 IServiceProvider *provider = IServiceProviderImpl_Construct();
2142 void *test_ptr = (void*)GetProcAddress(hShlwapi, "StrChrNW");
2143 static const GUID dummy_serviceid = { 0xdeadbeef };
2144 static const GUID dummy_groupid = { 0xbeefbeef };
2145 call_trace_t trace_expected;
2148 /* on <=W2K platforms same ordinal used for another export with different
2149 prototype, so skipping using this indirect condition */
2152 win_skip("IUnknown_QueryServiceExec is not available\n");
2156 /* null source pointer */
2157 hr = pIUnknown_QueryServiceExec(NULL, &dummy_serviceid, &dummy_groupid, 0, 0, 0, 0);
2158 ok(hr == E_FAIL, "got 0x%08x\n", hr);
2161 IUnknown_QueryServiceExec( ptr1, serviceid, groupid, arg1, arg2, arg3, arg4);
2162 -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &prov );
2163 -> IServiceProvider_QueryService( prov, serviceid, &IID_IOleCommandTarget, &obj );
2164 -> IOleCommandTarget_Exec( obj, groupid, arg1, arg2, arg3, arg4 );
2166 init_call_trace(&trace_expected);
2168 add_call(&trace_expected, 1, provider, &IID_IServiceProvider, 0, 0, 0);
2169 add_call(&trace_expected, 2, provider, &dummy_serviceid, &IID_IOleCommandTarget, 0, 0);
2170 add_call(&trace_expected, 3, &dummy_groupid, (void*)0x1, (void*)0x2, (void*)0x3, (void*)0x4);
2172 init_call_trace(&trace_got);
2173 hr = pIUnknown_QueryServiceExec((IUnknown*)provider, &dummy_serviceid, &dummy_groupid, 0x1, 0x2, (void*)0x3, (void*)0x4);
2174 ok(hr == S_OK, "got 0x%08x\n", hr);
2176 ok_trace(&trace_expected, &trace_got);
2178 free_call_trace(&trace_expected);
2179 free_call_trace(&trace_got);
2181 IServiceProvider_Release(provider);
2185 static HRESULT WINAPI IProfferServiceImpl_QueryInterface(IProfferService *iface, REFIID riid, void **ppvObj)
2187 IProfferServiceImpl *This = (IProfferServiceImpl *)iface;
2189 if (IsEqualIID(riid, &IID_IUnknown) ||
2190 IsEqualIID(riid, &IID_IProfferService))
2194 else if (IsEqualIID(riid, &IID_IServiceProvider))
2196 *ppvObj = IServiceProviderImpl_Construct();
2197 add_call(&trace_got, 1, iface, &IID_IServiceProvider, 0, 0, 0);
2203 IUnknown_AddRef(iface);
2207 return E_NOINTERFACE;
2210 static ULONG WINAPI IProfferServiceImpl_AddRef(IProfferService *iface)
2212 IProfferServiceImpl *This = (IProfferServiceImpl *)iface;
2213 return InterlockedIncrement(&This->ref);
2216 static ULONG WINAPI IProfferServiceImpl_Release(IProfferService *iface)
2218 IProfferServiceImpl *This = (IProfferServiceImpl *)iface;
2219 ULONG ref = InterlockedDecrement(&This->ref);
2223 HeapFree(GetProcessHeap(), 0, This);
2229 static HRESULT WINAPI IProfferServiceImpl_ProfferService(IProfferService *iface,
2230 REFGUID service, IServiceProvider *pService, DWORD *pCookie)
2232 add_call(&trace_got, 3, service, pService, pCookie, 0, 0);
2236 static HRESULT WINAPI IProfferServiceImpl_RevokeService(IProfferService *iface, DWORD cookie)
2238 add_call(&trace_got, 4, (void*)cookie, 0, 0, 0, 0);
2242 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl =
2244 IProfferServiceImpl_QueryInterface,
2245 IProfferServiceImpl_AddRef,
2246 IProfferServiceImpl_Release,
2247 IProfferServiceImpl_ProfferService,
2248 IProfferServiceImpl_RevokeService
2251 static void test_IUnknown_ProfferService(void)
2253 void *test_ptr = (void*)GetProcAddress(hShlwapi, "StrChrNW");
2254 IServiceProvider *provider = IServiceProviderImpl_Construct();
2255 IProfferService *proff = IProfferServiceImpl_Construct();
2256 static const GUID dummy_serviceid = { 0xdeadbeef };
2257 call_trace_t trace_expected;
2261 /* on <=W2K platforms same ordinal used for another export with different
2262 prototype, so skipping using this indirect condition */
2265 win_skip("IUnknown_ProfferService is not available\n");
2269 /* null source pointer */
2270 hr = pIUnknown_ProfferService(NULL, &dummy_serviceid, 0, 0);
2271 ok(hr == E_FAIL, "got 0x%08x\n", hr);
2274 IUnknown_ProfferService( ptr1, serviceid, arg1, arg2);
2275 -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &provider );
2276 -> IServiceProvider_QueryService( provider, &IID_IProfferService, &IID_IProfferService, &proffer );
2278 if (service pointer not null):
2279 -> IProfferService_ProfferService( proffer, serviceid, arg1, arg2 );
2281 -> IProfferService_RevokeService( proffer, *arg2 );
2283 init_call_trace(&trace_expected);
2285 add_call(&trace_expected, 1, proff, &IID_IServiceProvider, 0, 0, 0);
2286 add_call(&trace_expected, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2287 add_call(&trace_expected, 3, &dummy_serviceid, provider, &cookie, 0, 0);
2289 init_call_trace(&trace_got);
2290 hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, provider, &cookie);
2291 ok(hr == S_OK, "got 0x%08x\n", hr);
2293 ok_trace(&trace_expected, &trace_got);
2294 free_call_trace(&trace_got);
2295 free_call_trace(&trace_expected);
2297 /* same with ::Revoke path */
2298 init_call_trace(&trace_expected);
2300 add_call(&trace_expected, 1, proff, &IID_IServiceProvider, 0, 0, 0);
2301 add_call(&trace_expected, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2302 add_call(&trace_expected, 4, (void*)cookie, 0, 0, 0, 0);
2304 init_call_trace(&trace_got);
2305 hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, 0, &cookie);
2306 ok(hr == S_OK, "got 0x%08x\n", hr);
2307 ok_trace(&trace_expected, &trace_got);
2308 free_call_trace(&trace_got);
2309 free_call_trace(&trace_expected);
2311 IServiceProvider_Release(provider);
2312 IProfferService_Release(proff);
2315 static void init_pointers(void)
2317 #define MAKEFUNC(f, ord) (p##f = (void*)GetProcAddress(hShlwapi, (LPSTR)(ord)))
2318 MAKEFUNC(SHAllocShared, 7);
2319 MAKEFUNC(SHLockShared, 8);
2320 MAKEFUNC(SHUnlockShared, 9);
2321 MAKEFUNC(SHFreeShared, 10);
2322 MAKEFUNC(GetAcceptLanguagesA, 14);
2323 MAKEFUNC(SHSetWindowBits, 165);
2324 MAKEFUNC(ConnectToConnectionPoint, 168);
2325 MAKEFUNC(SHSearchMapInt, 198);
2326 MAKEFUNC(GUIDFromStringA, 269);
2327 MAKEFUNC(SHPackDispParams, 282);
2328 MAKEFUNC(IConnectionPoint_InvokeWithCancel, 283);
2329 MAKEFUNC(IConnectionPoint_SimpleInvoke, 284);
2330 MAKEFUNC(SHFormatDateTimeA, 353);
2331 MAKEFUNC(SHFormatDateTimeW, 354);
2332 MAKEFUNC(SHGetObjectCompatFlags, 476);
2333 MAKEFUNC(IUnknown_QueryServiceExec, 484);
2334 MAKEFUNC(SHPropertyBag_ReadLONG, 496);
2335 MAKEFUNC(IUnknown_ProfferService, 514);
2341 hShlwapi = GetModuleHandleA("shlwapi.dll");
2345 hmlang = LoadLibraryA("mlang.dll");
2346 pLcidToRfc1766A = (void *)GetProcAddress(hmlang, "LcidToRfc1766A");
2348 test_GetAcceptLanguagesA();
2349 test_SHSearchMapInt();
2350 test_alloc_shared();
2352 test_GetShellSecurityDescriptor();
2353 test_SHPackDispParams();
2354 test_IConnectionPoint();
2355 test_SHPropertyBag_ReadLONG();
2356 test_SHSetWindowBits();
2357 test_SHFormatDateTimeA();
2358 test_SHFormatDateTimeW();
2359 test_SHGetObjectCompatFlags();
2360 test_IUnknown_QueryServiceExec();
2361 test_IUnknown_ProfferService();