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
20 #define WIN32_NO_STATUS
22 #define COM_NO_WINDOWS_H
28 #include <wine/test.h>
29 //#include "winbase.h"
32 //#include "winerror.h"
33 //#include "winuser.h"
43 /* Function ptrs for ordinal calls */
44 static HMODULE hShlwapi
;
45 static BOOL is_win2k_and_lower
;
48 static int (WINAPI
*pSHSearchMapInt
)(const int*,const int*,int,int);
49 static HRESULT (WINAPI
*pGetAcceptLanguagesA
)(LPSTR
,LPDWORD
);
51 static HANDLE (WINAPI
*pSHAllocShared
)(LPCVOID
,DWORD
,DWORD
);
52 static LPVOID (WINAPI
*pSHLockShared
)(HANDLE
,DWORD
);
53 static BOOL (WINAPI
*pSHUnlockShared
)(LPVOID
);
54 static BOOL (WINAPI
*pSHFreeShared
)(HANDLE
,DWORD
);
55 static HANDLE (WINAPI
*pSHMapHandle
)(HANDLE
,DWORD
,DWORD
,DWORD
,DWORD
);
56 static HRESULT(WINAPIV
*pSHPackDispParams
)(DISPPARAMS
*,VARIANTARG
*,UINT
,...);
57 static HRESULT(WINAPI
*pIConnectionPoint_SimpleInvoke
)(IConnectionPoint
*,DISPID
,DISPPARAMS
*);
58 static HRESULT(WINAPI
*pIConnectionPoint_InvokeWithCancel
)(IConnectionPoint
*,DISPID
,DISPPARAMS
*,DWORD
,DWORD
);
59 static HRESULT(WINAPI
*pConnectToConnectionPoint
)(IUnknown
*,REFIID
,BOOL
,IUnknown
*, LPDWORD
,IConnectionPoint
**);
60 static HRESULT(WINAPI
*pSHPropertyBag_ReadLONG
)(IPropertyBag
*,LPCWSTR
,LPLONG
);
61 static LONG (WINAPI
*pSHSetWindowBits
)(HWND
, INT
, UINT
, UINT
);
62 static INT (WINAPI
*pSHFormatDateTimeA
)(const FILETIME UNALIGNED
*, DWORD
*, LPSTR
, UINT
);
63 static INT (WINAPI
*pSHFormatDateTimeW
)(const FILETIME UNALIGNED
*, DWORD
*, LPWSTR
, UINT
);
64 static DWORD (WINAPI
*pSHGetObjectCompatFlags
)(IUnknown
*, const CLSID
*);
65 static BOOL (WINAPI
*pGUIDFromStringA
)(LPSTR
, CLSID
*);
66 static HRESULT (WINAPI
*pIUnknown_QueryServiceExec
)(IUnknown
*, REFIID
, const GUID
*, DWORD
, DWORD
, VARIANT
*, VARIANT
*);
67 static HRESULT (WINAPI
*pIUnknown_ProfferService
)(IUnknown
*, REFGUID
, IServiceProvider
*, DWORD
*);
68 static HWND (WINAPI
*pSHCreateWorkerWindowA
)(LONG
, HWND
, DWORD
, DWORD
, HMENU
, LONG_PTR
);
69 static HRESULT (WINAPI
*pSHIShellFolder_EnumObjects
)(LPSHELLFOLDER
, HWND
, SHCONTF
, IEnumIDList
**);
70 static DWORD (WINAPI
*pSHGetIniStringW
)(LPCWSTR
, LPCWSTR
, LPWSTR
, DWORD
, LPCWSTR
);
71 static BOOL (WINAPI
*pSHSetIniStringW
)(LPCWSTR
, LPCWSTR
, LPCWSTR
, LPCWSTR
);
72 static HKEY (WINAPI
*pSHGetShellKey
)(DWORD
, LPCWSTR
, BOOL
);
73 static HRESULT (WINAPI
*pSKGetValueW
)(DWORD
, LPCWSTR
, LPCWSTR
, DWORD
*, void*, DWORD
*);
74 static HRESULT (WINAPI
*pSKSetValueW
)(DWORD
, LPCWSTR
, LPCWSTR
, DWORD
, void*, DWORD
);
75 static HRESULT (WINAPI
*pSKDeleteValueW
)(DWORD
, LPCWSTR
, LPCWSTR
);
76 static HRESULT (WINAPI
*pSKAllocValueW
)(DWORD
, LPCWSTR
, LPCWSTR
, DWORD
*, void**, DWORD
*);
77 static HWND (WINAPI
*pSHSetParentHwnd
)(HWND
, HWND
);
78 static HRESULT (WINAPI
*pIUnknown_GetClassID
)(IUnknown
*, CLSID
*);
79 static HRESULT (WINAPI
*pDllGetVersion
)(DLLVERSIONINFO2
*);
81 typedef struct SHELL_USER_SID
{
82 SID_IDENTIFIER_AUTHORITY sidAuthority
;
85 } SHELL_USER_SID
, *PSHELL_USER_SID
;
86 typedef struct SHELL_USER_PERMISSION
{
93 DWORD dwInheritAccessMask
;
94 } SHELL_USER_PERMISSION
, *PSHELL_USER_PERMISSION
;
96 static SECURITY_DESCRIPTOR
* (WINAPI
*pGetShellSecurityDescriptor
)(const SHELL_USER_PERMISSION
**,int);
98 static HMODULE hmlang
;
99 static HRESULT (WINAPI
*pLcidToRfc1766A
)(LCID
, LPSTR
, INT
);
101 static HMODULE hshell32
;
102 static HRESULT (WINAPI
*pSHGetDesktopFolder
)(IShellFolder
**);
104 static const CHAR ie_international
[] = {
105 'S','o','f','t','w','a','r','e','\\',
106 'M','i','c','r','o','s','o','f','t','\\',
107 'I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r','\\',
108 'I','n','t','e','r','n','a','t','i','o','n','a','l',0};
109 static const CHAR acceptlanguage
[] = {
110 'A','c','c','e','p','t','L','a','n','g','u','a','g','e',0};
112 static int strcmp_wa(LPCWSTR strw
, const char *stra
)
115 WideCharToMultiByte(CP_ACP
, 0, strw
, -1, buf
, sizeof(buf
), NULL
, NULL
);
116 return lstrcmpA(stra
, buf
);
130 static void init_call_trace(call_trace_t
*ctrace
)
134 ctrace
->calls
= HeapAlloc(GetProcessHeap(), 0, sizeof(call_entry_t
) * ctrace
->alloc
);
137 static void free_call_trace(const call_trace_t
*ctrace
)
139 HeapFree(GetProcessHeap(), 0, ctrace
->calls
);
142 static void add_call(call_trace_t
*ctrace
, int id
, const void *arg0
,
143 const void *arg1
, const void *arg2
, const void *arg3
, const void *arg4
)
154 if (ctrace
->count
== ctrace
->alloc
)
157 ctrace
->calls
= HeapReAlloc(GetProcessHeap(),0, ctrace
->calls
, ctrace
->alloc
*sizeof(call_entry_t
));
160 ctrace
->calls
[ctrace
->count
++] = call
;
163 static void ok_trace_(call_trace_t
*texpected
, call_trace_t
*tgot
, int line
)
165 if (texpected
->count
== tgot
->count
)
169 for (i
= 0; i
< texpected
->count
; i
++)
171 call_entry_t
*expected
= &texpected
->calls
[i
];
172 call_entry_t
*got
= &tgot
->calls
[i
];
175 ok_(__FILE__
, line
)(expected
->id
== got
->id
, "got different ids %d: %d, %d\n", i
+1, expected
->id
, got
->id
);
177 for (j
= 0; j
< 5; j
++)
179 ok_(__FILE__
, line
)(expected
->args
[j
] == got
->args
[j
], "got different args[%d] for %d: %p, %p\n", j
, i
+1,
180 expected
->args
[j
], got
->args
[j
]);
185 ok_(__FILE__
, line
)(0, "traces length mismatch\n");
188 #define ok_trace(a, b) ok_trace_(a, b, __LINE__)
190 /* trace of actually made calls */
191 static call_trace_t trace_got
;
193 static void test_GetAcceptLanguagesA(void)
195 static LPCSTR table
[] = {"de,en-gb;q=0.7,en;q=0.3",
196 "de,en;q=0.3,en-gb;q=0.7", /* sorting is ignored */
197 "winetest", /* content is ignored */
207 LONG res_query
= ERROR_SUCCESS
;
210 DWORD maxlen
= sizeof(buffer
) - 2;
216 if (!pGetAcceptLanguagesA
) {
217 win_skip("GetAcceptLanguagesA is not available\n");
221 lcid
= GetUserDefaultLCID();
223 /* Get the original Value */
224 lres
= RegOpenKeyA(HKEY_CURRENT_USER
, ie_international
, &hroot
);
226 skip("RegOpenKey(%s) failed: %d\n", ie_international
, lres
);
229 len
= sizeof(original
);
231 res_query
= RegQueryValueExA(hroot
, acceptlanguage
, 0, NULL
, (PBYTE
)original
, &len
);
233 RegDeleteValueA(hroot
, acceptlanguage
);
235 /* Some windows versions use "lang-COUNTRY" as default */
236 memset(language
, 0, sizeof(language
));
237 len
= GetLocaleInfoA(lcid
, LOCALE_SISO639LANGNAME
, language
, sizeof(language
));
240 lstrcatA(language
, "-");
241 memset(buffer
, 0, sizeof(buffer
));
242 len
= GetLocaleInfoA(lcid
, LOCALE_SISO3166CTRYNAME
, buffer
, sizeof(buffer
) - len
- 1);
243 lstrcatA(language
, buffer
);
247 /* LOCALE_SNAME has additional parts in some languages. Try only as last chance */
248 memset(language
, 0, sizeof(language
));
249 len
= GetLocaleInfoA(lcid
, LOCALE_SNAME
, language
, sizeof(language
));
252 /* get the default value */
254 memset(buffer
, '#', maxlen
);
256 hr
= pGetAcceptLanguagesA( buffer
, &len
);
259 win_skip("GetAcceptLanguagesA failed with 0x%x\n", hr
);
260 goto restore_original
;
263 if (lstrcmpA(buffer
, language
)) {
264 /* some windows versions use "lang" or "lang-country" as default */
266 if (pLcidToRfc1766A
) {
267 hr
= pLcidToRfc1766A(lcid
, language
, sizeof(language
));
268 ok(hr
== S_OK
, "LcidToRfc1766A returned 0x%x and %s\n", hr
, language
);
272 ok(!lstrcmpA(buffer
, language
),
273 "have '%s' (searching for '%s')\n", language
, buffer
);
275 if (lstrcmpA(buffer
, language
)) {
276 win_skip("no more ideas, how to build the default language '%s'\n", buffer
);
277 goto restore_original
;
280 trace("detected default: %s\n", language
);
281 while ((entry
= table
[i
])) {
283 exactsize
= lstrlenA(entry
);
285 lres
= RegSetValueExA(hroot
, acceptlanguage
, 0, REG_SZ
, (const BYTE
*) entry
, exactsize
+ 1);
286 ok(!lres
, "got %d for RegSetValueExA: %s\n", lres
, entry
);
288 /* len includes space for the terminating 0 before vista/w2k8 */
290 memset(buffer
, '#', maxlen
);
292 hr
= pGetAcceptLanguagesA( buffer
, &len
);
293 ok(((hr
== E_INVALIDARG
) && (len
== 0)) ||
295 ((len
== exactsize
) || (len
== exactsize
+1)) &&
296 !lstrcmpA(buffer
, entry
)),
297 "+2_#%d: got 0x%x with %d and %s\n", i
, hr
, len
, buffer
);
300 memset(buffer
, '#', maxlen
);
302 hr
= pGetAcceptLanguagesA( buffer
, &len
);
303 ok(((hr
== E_INVALIDARG
) && (len
== 0)) ||
305 ((len
== exactsize
) || (len
== exactsize
+1)) &&
306 !lstrcmpA(buffer
, entry
)),
307 "+1_#%d: got 0x%x with %d and %s\n", i
, hr
, len
, buffer
);
310 memset(buffer
, '#', maxlen
);
312 hr
= pGetAcceptLanguagesA( buffer
, &len
);
314 /* There is no space for the string in the registry.
315 When the buffer is large enough, the default language is returned
317 When the buffer is too small for that fallback, win7_32 and w2k8_64
318 fail with E_NOT_SUFFICIENT_BUFFER, win8 fails with HRESULT_FROM_WIN32(ERROR_MORE_DATA),
319 other versions succeed and return a partial result while older os succeed
320 and overflow the buffer */
322 ok(((hr
== E_INVALIDARG
) && (len
== 0)) ||
323 (((hr
== S_OK
) && !lstrcmpA(buffer
, language
) && (len
== lstrlenA(language
))) ||
324 ((hr
== S_OK
) && !memcmp(buffer
, language
, len
)) ||
325 ((hr
== E_NOT_SUFFICIENT_BUFFER
) && !len
) ||
326 ((hr
== __HRESULT_FROM_WIN32(ERROR_MORE_DATA
)) && len
== exactsize
)),
327 "==_#%d: got 0x%x with %d and %s\n", i
, hr
, len
, buffer
);
331 memset(buffer
, '#', maxlen
);
333 hr
= pGetAcceptLanguagesA( buffer
, &len
);
334 ok(((hr
== E_INVALIDARG
) && (len
== 0)) ||
335 (((hr
== S_OK
) && !lstrcmpA(buffer
, language
) && (len
== lstrlenA(language
))) ||
336 ((hr
== S_OK
) && !memcmp(buffer
, language
, len
)) ||
337 ((hr
== E_NOT_SUFFICIENT_BUFFER
) && !len
) ||
338 ((hr
== __HRESULT_FROM_WIN32(ERROR_MORE_DATA
)) && len
== exactsize
- 1)),
339 "-1_#%d: got 0x%x with %d and %s\n", i
, hr
, len
, buffer
);
343 memset(buffer
, '#', maxlen
);
345 hr
= pGetAcceptLanguagesA( buffer
, &len
);
346 ok(((hr
== E_INVALIDARG
) && (len
== 0)) ||
347 (((hr
== S_OK
) && !lstrcmpA(buffer
, language
) && (len
== lstrlenA(language
))) ||
348 ((hr
== S_OK
) && !memcmp(buffer
, language
, len
)) ||
349 ((hr
== E_NOT_SUFFICIENT_BUFFER
) && !len
) ||
350 ((hr
== __HRESULT_FROM_WIN32(ERROR_MORE_DATA
)) && len
== 1)),
351 "=1_#%d: got 0x%x with %d and %s\n", i
, hr
, len
, buffer
);
354 hr
= pGetAcceptLanguagesA( NULL
, &len
);
356 /* w2k3 and below: E_FAIL and untouched len,
357 since w2k8: S_OK and needed size (excluding 0), win8 S_OK and size including 0. */
358 ok( ((hr
== S_OK
) && ((len
== exactsize
) || (len
== exactsize
+ 1))) ||
359 ((hr
== E_FAIL
) && (len
== maxlen
)),
360 "NULL,max #%d: got 0x%x with %d and %s\n", i
, hr
, len
, buffer
);
365 /* without a value in the registry, a default language is returned */
366 RegDeleteValueA(hroot
, acceptlanguage
);
369 memset(buffer
, '#', maxlen
);
371 hr
= pGetAcceptLanguagesA( buffer
, &len
);
372 ok( ((hr
== S_OK
) && (len
== lstrlenA(language
))),
373 "max: got 0x%x with %d and %s (expected S_OK with %d and '%s'\n",
374 hr
, len
, buffer
, lstrlenA(language
), language
);
377 memset(buffer
, '#', maxlen
);
379 hr
= pGetAcceptLanguagesA( buffer
, &len
);
380 ok( (((hr
== S_OK
) || (hr
== E_INVALIDARG
)) && !memcmp(buffer
, language
, len
)) ||
381 ((hr
== E_NOT_SUFFICIENT_BUFFER
) && !len
) ||
382 ((hr
== __HRESULT_FROM_WIN32(ERROR_CANNOT_COPY
)) && !len
),
383 "=2: got 0x%x with %d and %s\n", hr
, len
, buffer
);
386 memset(buffer
, '#', maxlen
);
388 hr
= pGetAcceptLanguagesA( buffer
, &len
);
389 /* When the buffer is too small, win7_32 and w2k8_64 and above fail with
390 E_NOT_SUFFICIENT_BUFFER, win8 ERROR_CANNOT_COPY,
391 other versions succeed and return a partial 0 terminated result while other versions
392 fail with E_INVALIDARG and return a partial unterminated result */
393 ok( (((hr
== S_OK
) || (hr
== E_INVALIDARG
)) && !memcmp(buffer
, language
, len
)) ||
394 ((hr
== E_NOT_SUFFICIENT_BUFFER
) && !len
) ||
395 ((hr
== __HRESULT_FROM_WIN32(ERROR_CANNOT_COPY
)) && !len
),
396 "=1: got 0x%x with %d and %s\n", hr
, len
, buffer
);
399 memset(buffer
, '#', maxlen
);
401 hr
= pGetAcceptLanguagesA( buffer
, &len
);
402 /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG, win8 ERROR_CANNOT_COPY */
403 ok((hr
== E_FAIL
) || (hr
== E_INVALIDARG
) || (hr
== __HRESULT_FROM_WIN32(ERROR_CANNOT_COPY
)),
406 memset(buffer
, '#', maxlen
);
408 hr
= pGetAcceptLanguagesA( buffer
, NULL
);
409 /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG */
410 ok((hr
== E_FAIL
) || (hr
== E_INVALIDARG
),
411 "got 0x%x (expected E_FAIL or E_INVALIDARG)\n", hr
);
414 hr
= pGetAcceptLanguagesA( NULL
, NULL
);
415 /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG */
416 ok((hr
== E_FAIL
) || (hr
== E_INVALIDARG
),
417 "got 0x%x (expected E_FAIL or E_INVALIDARG)\n", hr
);
421 len
= lstrlenA(original
);
422 lres
= RegSetValueExA(hroot
, acceptlanguage
, 0, REG_SZ
, (const BYTE
*) original
, len
? len
+ 1: 0);
423 ok(!lres
, "RegSetValueEx(%s) failed: %d\n", original
, lres
);
427 RegDeleteValueA(hroot
, acceptlanguage
);
432 static void test_SHSearchMapInt(void)
434 int keys
[8], values
[8];
437 if (!pSHSearchMapInt
)
440 memset(keys
, 0, sizeof(keys
));
441 memset(values
, 0, sizeof(values
));
442 keys
[0] = 99; values
[0] = 101;
444 /* NULL key/value lists crash native, so skip testing them */
447 i
= pSHSearchMapInt(keys
, values
, 1, keys
[0]);
448 ok(i
== values
[0], "Len 1, expected %d, got %d\n", values
[0], i
);
450 /* Key doesn't exist */
451 i
= pSHSearchMapInt(keys
, values
, 1, 100);
452 ok(i
== -1, "Len 1 - bad key, expected -1, got %d\n", i
);
454 /* Len = 0 => not found */
455 i
= pSHSearchMapInt(keys
, values
, 0, keys
[0]);
456 ok(i
== -1, "Len 1 - passed len 0, expected -1, got %d\n", i
);
458 /* 2 elements, len = 1 */
459 keys
[1] = 98; values
[1] = 102;
460 i
= pSHSearchMapInt(keys
, values
, 1, keys
[1]);
461 ok(i
== -1, "Len 1 - array len 2, expected -1, got %d\n", i
);
463 /* 2 elements, len = 2 */
464 i
= pSHSearchMapInt(keys
, values
, 2, keys
[1]);
465 ok(i
== values
[1], "Len 2, expected %d, got %d\n", values
[1], i
);
467 /* Searches forward */
468 keys
[2] = 99; values
[2] = 103;
469 i
= pSHSearchMapInt(keys
, values
, 3, keys
[0]);
470 ok(i
== values
[0], "Len 3, expected %d, got %d\n", values
[0], i
);
479 static void test_alloc_shared(int argc
, char **argv
)
481 char cmdline
[MAX_PATH
];
482 PROCESS_INFORMATION pi
;
483 STARTUPINFOA si
= { 0 };
485 HANDLE hmem
, hmem2
= 0;
486 struct shared_struct val
, *p
;
489 procid
=GetCurrentProcessId();
490 hmem
=pSHAllocShared(NULL
,10,procid
);
491 ok(hmem
!=NULL
,"SHAllocShared(NULL...) failed: %u\n", GetLastError());
492 ret
= pSHFreeShared(hmem
, procid
);
493 ok( ret
, "SHFreeShared failed: %u\n", GetLastError());
495 val
.value
= 0x12345678;
497 hmem
= pSHAllocShared(&val
, sizeof(val
), procid
);
498 ok(hmem
!=NULL
,"SHAllocShared(NULL...) failed: %u\n", GetLastError());
500 p
=pSHLockShared(hmem
,procid
);
501 ok(p
!=NULL
,"SHLockShared failed: %u\n", GetLastError());
503 ok(p
->value
== 0x12345678, "Wrong value in shared memory: %d instead of %d\n", p
->value
, 0x12345678);
504 ret
= pSHUnlockShared(p
);
505 ok( ret
, "SHUnlockShared failed: %u\n", GetLastError());
507 sprintf(cmdline
, "%s %s %d %p", argv
[0], argv
[1], procid
, hmem
);
508 ret
= CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
509 ok(ret
, "could not create child process error: %u\n", GetLastError());
512 winetest_wait_child_process(pi
.hProcess
);
513 CloseHandle(pi
.hThread
);
514 CloseHandle(pi
.hProcess
);
516 p
= pSHLockShared(hmem
, procid
);
517 ok(p
!= NULL
,"SHLockShared failed: %u\n", GetLastError());
518 if (p
!= NULL
&& p
->value
!= 0x12345678)
520 ok(p
->value
== 0x12345679, "Wrong value in shared memory: %d instead of %d\n", p
->value
, 0x12345679);
522 ok(hmem2
!= NULL
, "Expected handle in shared memory\n");
524 ret
= pSHUnlockShared(p
);
525 ok(ret
, "SHUnlockShared failed: %u\n", GetLastError());
528 ret
= pSHFreeShared(hmem
, procid
);
529 ok( ret
, "SHFreeShared failed: %u\n", GetLastError());
533 p
= pSHLockShared(hmem2
, procid
);
534 ok(p
!= NULL
,"SHLockShared failed: %u\n", GetLastError());
536 ok(p
->value
== 0xDEADBEEF, "Wrong value in shared memory: %d instead of %d\n", p
->value
, 0xDEADBEEF);
537 ret
= pSHUnlockShared(p
);
538 ok(ret
, "SHUnlockShared failed: %u\n", GetLastError());
540 ret
= pSHFreeShared(hmem2
, procid
);
541 ok(ret
, "SHFreeShared failed: %u\n", GetLastError());
544 SetLastError(0xdeadbeef);
545 ret
= pSHFreeShared(NULL
, procid
);
546 ok(ret
, "SHFreeShared failed: %u\n", GetLastError());
547 ok(GetLastError() == 0xdeadbeef, "last error should not have changed, got %u\n", GetLastError());
550 static void test_alloc_shared_remote(DWORD procid
, HANDLE hmem
)
552 struct shared_struct val
, *p
;
556 /* test directly accessing shared memory of a remote process */
557 p
= pSHLockShared(hmem
, procid
);
558 ok(p
!= NULL
|| broken(p
== NULL
) /* Windows 7/8 */, "SHLockShared failed: %u\n", GetLastError());
561 win_skip("Subprocess failed to modify shared memory, skipping test\n");
565 ok(p
->value
== 0x12345678, "Wrong value in shared memory: %d instead of %d\n", p
->value
, 0x12345678);
568 val
.value
= 0xDEADBEEF;
570 p
->handle
= pSHAllocShared(&val
, sizeof(val
), procid
);
571 ok(p
->handle
!= NULL
, "SHAllocShared failed: %u\n", GetLastError());
573 ret
= pSHUnlockShared(p
);
574 ok(ret
, "SHUnlockShared failed: %u\n", GetLastError());
576 /* test SHMapHandle */
577 SetLastError(0xdeadbeef);
578 hmem2
= pSHMapHandle(NULL
, procid
, GetCurrentProcessId(), 0, 0);
579 ok(hmem2
== NULL
, "expected NULL, got new handle\n");
580 ok(GetLastError() == 0xdeadbeef, "last error should not have changed, got %u\n", GetLastError());
582 hmem2
= pSHMapHandle(hmem
, procid
, GetCurrentProcessId(), 0, 0);
584 /* It seems like Windows Vista/2008 uses a different internal implementation
585 * for shared memory, and calling SHMapHandle fails. */
586 ok(hmem2
!= NULL
|| broken(hmem2
== NULL
),
587 "SHMapHandle failed: %u\n", GetLastError());
590 win_skip("Subprocess failed to map shared memory, skipping test\n");
594 p
= pSHLockShared(hmem2
, GetCurrentProcessId());
595 ok(p
!= NULL
, "SHLockShared failed: %u\n", GetLastError());
598 ok(p
->value
== 0x12345679, "Wrong value in shared memory: %d instead of %d\n", p
->value
, 0x12345679);
600 ret
= pSHUnlockShared(p
);
601 ok(ret
, "SHUnlockShared failed: %u\n", GetLastError());
603 ret
= pSHFreeShared(hmem2
, GetCurrentProcessId());
604 ok(ret
, "SHFreeShared failed: %u\n", GetLastError());
607 static void test_fdsa(void)
611 DWORD num_items
; /* Number of elements inserted */
612 void *mem
; /* Ptr to array */
613 DWORD blocks_alloced
; /* Number of elements allocated */
614 BYTE inc
; /* Number of elements to grow by when we need to expand */
615 BYTE block_size
; /* Size in bytes of an element */
616 BYTE flags
; /* Flags */
619 BOOL (WINAPI
*pFDSA_Initialize
)(DWORD block_size
, DWORD inc
, FDSA_info
*info
, void *mem
,
621 BOOL (WINAPI
*pFDSA_Destroy
)(FDSA_info
*info
);
622 DWORD (WINAPI
*pFDSA_InsertItem
)(FDSA_info
*info
, DWORD where
, const void *block
);
623 BOOL (WINAPI
*pFDSA_DeleteItem
)(FDSA_info
*info
, DWORD where
);
626 int block_size
= 10, init_blocks
= 4, inc
= 2;
630 pFDSA_Initialize
= (void *)GetProcAddress(hShlwapi
, (LPSTR
)208);
631 pFDSA_Destroy
= (void *)GetProcAddress(hShlwapi
, (LPSTR
)209);
632 pFDSA_InsertItem
= (void *)GetProcAddress(hShlwapi
, (LPSTR
)210);
633 pFDSA_DeleteItem
= (void *)GetProcAddress(hShlwapi
, (LPSTR
)211);
635 mem
= HeapAlloc(GetProcessHeap(), 0, block_size
* init_blocks
);
636 memset(&info
, 0, sizeof(info
));
638 ok(pFDSA_Initialize(block_size
, inc
, &info
, mem
, init_blocks
), "FDSA_Initialize rets FALSE\n");
639 ok(info
.num_items
== 0, "num_items = %d\n", info
.num_items
);
640 ok(info
.mem
== mem
, "mem = %p\n", info
.mem
);
641 ok(info
.blocks_alloced
== init_blocks
, "blocks_alloced = %d\n", info
.blocks_alloced
);
642 ok(info
.inc
== inc
, "inc = %d\n", info
.inc
);
643 ok(info
.block_size
== block_size
, "block_size = %d\n", info
.block_size
);
644 ok(info
.flags
== 0, "flags = %d\n", info
.flags
);
646 ret
= pFDSA_InsertItem(&info
, 1234, "1234567890");
647 ok(ret
== 0, "ret = %d\n", ret
);
648 ok(info
.num_items
== 1, "num_items = %d\n", info
.num_items
);
649 ok(info
.mem
== mem
, "mem = %p\n", info
.mem
);
650 ok(info
.blocks_alloced
== init_blocks
, "blocks_alloced = %d\n", info
.blocks_alloced
);
651 ok(info
.inc
== inc
, "inc = %d\n", info
.inc
);
652 ok(info
.block_size
== block_size
, "block_size = %d\n", info
.block_size
);
653 ok(info
.flags
== 0, "flags = %d\n", info
.flags
);
655 ret
= pFDSA_InsertItem(&info
, 1234, "abcdefghij");
656 ok(ret
== 1, "ret = %d\n", ret
);
658 ret
= pFDSA_InsertItem(&info
, 1, "klmnopqrst");
659 ok(ret
== 1, "ret = %d\n", ret
);
661 ret
= pFDSA_InsertItem(&info
, 0, "uvwxyzABCD");
662 ok(ret
== 0, "ret = %d\n", ret
);
663 ok(info
.mem
== mem
, "mem = %p\n", info
.mem
);
664 ok(info
.flags
== 0, "flags = %d\n", info
.flags
);
666 /* This next InsertItem will cause shlwapi to allocate its own mem buffer */
667 ret
= pFDSA_InsertItem(&info
, 0, "EFGHIJKLMN");
668 ok(ret
== 0, "ret = %d\n", ret
);
669 ok(info
.mem
!= mem
, "mem = %p\n", info
.mem
);
670 ok(info
.blocks_alloced
== init_blocks
+ inc
, "blocks_alloced = %d\n", info
.blocks_alloced
);
671 ok(info
.flags
== 0x1, "flags = %d\n", info
.flags
);
673 ok(!memcmp(info
.mem
, "EFGHIJKLMNuvwxyzABCD1234567890klmnopqrstabcdefghij", 50), "mem %s\n", (char*)info
.mem
);
675 ok(pFDSA_DeleteItem(&info
, 2), "rets FALSE\n");
676 ok(info
.mem
!= mem
, "mem = %p\n", info
.mem
);
677 ok(info
.blocks_alloced
== init_blocks
+ inc
, "blocks_alloced = %d\n", info
.blocks_alloced
);
678 ok(info
.flags
== 0x1, "flags = %d\n", info
.flags
);
680 ok(!memcmp(info
.mem
, "EFGHIJKLMNuvwxyzABCDklmnopqrstabcdefghij", 40), "mem %s\n", (char*)info
.mem
);
682 ok(pFDSA_DeleteItem(&info
, 3), "rets FALSE\n");
683 ok(info
.mem
!= mem
, "mem = %p\n", info
.mem
);
684 ok(info
.blocks_alloced
== init_blocks
+ inc
, "blocks_alloced = %d\n", info
.blocks_alloced
);
685 ok(info
.flags
== 0x1, "flags = %d\n", info
.flags
);
687 ok(!memcmp(info
.mem
, "EFGHIJKLMNuvwxyzABCDklmnopqrst", 30), "mem %s\n", (char*)info
.mem
);
689 ok(!pFDSA_DeleteItem(&info
, 4), "does not ret FALSE\n");
691 /* As shlwapi has allocated memory internally, Destroy will ret FALSE */
692 ok(!pFDSA_Destroy(&info
), "FDSA_Destroy does not ret FALSE\n");
695 /* When Initialize is called with inc = 0, set it to 1 */
696 ok(pFDSA_Initialize(block_size
, 0, &info
, mem
, init_blocks
), "FDSA_Initialize rets FALSE\n");
697 ok(info
.inc
== 1, "inc = %d\n", info
.inc
);
699 /* This time, because shlwapi hasn't had to allocate memory
700 internally, Destroy rets non-zero */
701 ok(pFDSA_Destroy(&info
), "FDSA_Destroy rets FALSE\n");
704 HeapFree(GetProcessHeap(), 0, mem
);
707 static void test_GetShellSecurityDescriptor(void)
709 static const SHELL_USER_PERMISSION supCurrentUserFull
= {
710 { {SECURITY_NULL_SID_AUTHORITY
}, 0, 0 },
711 ACCESS_ALLOWED_ACE_TYPE
, FALSE
,
713 #define MY_INHERITANCE 0xBE /* invalid value to proof behavior */
714 static const SHELL_USER_PERMISSION supEveryoneDenied
= {
715 { {SECURITY_WORLD_SID_AUTHORITY
}, SECURITY_WORLD_RID
, 0 },
716 ACCESS_DENIED_ACE_TYPE
, TRUE
,
717 GENERIC_WRITE
, MY_INHERITANCE
| 0xDEADBA00, GENERIC_READ
};
718 const SHELL_USER_PERMISSION
* rgsup
[2] = {
719 &supCurrentUserFull
, &supEveryoneDenied
,
721 SECURITY_DESCRIPTOR
* psd
;
722 void *pChrCmpIW
= GetProcAddress(hShlwapi
, "ChrCmpIW");
724 if(!pGetShellSecurityDescriptor
)
726 win_skip("GetShellSecurityDescriptor not available\n");
730 if(pChrCmpIW
&& pChrCmpIW
== pGetShellSecurityDescriptor
) /* win2k */
732 win_skip("Skipping for GetShellSecurityDescriptor, same ordinal used for ChrCmpIW\n");
736 psd
= pGetShellSecurityDescriptor(NULL
, 2);
738 broken(psd
==INVALID_HANDLE_VALUE
), /* IE5 */
739 "GetShellSecurityDescriptor should fail\n");
740 psd
= pGetShellSecurityDescriptor(rgsup
, 0);
741 ok(psd
==NULL
, "GetShellSecurityDescriptor should fail, got %p\n", psd
);
743 SetLastError(0xdeadbeef);
744 psd
= pGetShellSecurityDescriptor(rgsup
, 2);
745 if (psd
== NULL
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
747 /* The previous calls to GetShellSecurityDescriptor don't set the last error */
748 win_skip("GetShellSecurityDescriptor is not implemented\n");
751 if (psd
== INVALID_HANDLE_VALUE
)
753 win_skip("GetShellSecurityDescriptor is broken on IE5\n");
756 ok(psd
!=NULL
, "GetShellSecurityDescriptor failed\n");
759 BOOL bHasDacl
= FALSE
, bDefaulted
, ret
;
762 SECURITY_DESCRIPTOR_CONTROL control
;
764 ok(IsValidSecurityDescriptor(psd
), "returned value is not valid SD\n");
766 ret
= GetSecurityDescriptorControl(psd
, &control
, &dwRev
);
767 ok(ret
, "GetSecurityDescriptorControl failed with error %u\n", GetLastError());
768 ok(0 == (control
& SE_SELF_RELATIVE
), "SD should be absolute\n");
770 ret
= GetSecurityDescriptorDacl(psd
, &bHasDacl
, &pAcl
, &bDefaulted
);
771 ok(ret
, "GetSecurityDescriptorDacl failed with error %u\n", GetLastError());
773 ok(bHasDacl
, "SD has no DACL\n");
776 ok(!bDefaulted
, "DACL should not be defaulted\n");
778 ok(pAcl
!= NULL
, "NULL DACL!\n");
781 ACL_SIZE_INFORMATION asiSize
;
783 ok(IsValidAcl(pAcl
), "DACL is not valid\n");
785 ret
= GetAclInformation(pAcl
, &asiSize
, sizeof(asiSize
), AclSizeInformation
);
786 ok(ret
, "GetAclInformation failed with error %u\n", GetLastError());
788 ok(asiSize
.AceCount
== 3, "Incorrect number of ACEs: %d entries\n", asiSize
.AceCount
);
789 if (asiSize
.AceCount
== 3)
791 ACCESS_ALLOWED_ACE
*paaa
; /* will use for DENIED too */
793 ret
= GetAce(pAcl
, 0, (LPVOID
*)&paaa
);
794 ok(ret
, "GetAce failed with error %u\n", GetLastError());
795 ok(paaa
->Header
.AceType
== ACCESS_ALLOWED_ACE_TYPE
,
796 "Invalid ACE type %d\n", paaa
->Header
.AceType
);
797 ok(paaa
->Header
.AceFlags
== 0, "Invalid ACE flags %x\n", paaa
->Header
.AceFlags
);
798 ok(paaa
->Mask
== GENERIC_ALL
, "Invalid ACE mask %x\n", paaa
->Mask
);
800 ret
= GetAce(pAcl
, 1, (LPVOID
*)&paaa
);
801 ok(ret
, "GetAce failed with error %u\n", GetLastError());
802 ok(paaa
->Header
.AceType
== ACCESS_DENIED_ACE_TYPE
,
803 "Invalid ACE type %d\n", paaa
->Header
.AceType
);
804 /* first one of two ACEs generated from inheritable entry - without inheritance */
805 ok(paaa
->Header
.AceFlags
== 0, "Invalid ACE flags %x\n", paaa
->Header
.AceFlags
);
806 ok(paaa
->Mask
== GENERIC_WRITE
, "Invalid ACE mask %x\n", paaa
->Mask
);
808 ret
= GetAce(pAcl
, 2, (LPVOID
*)&paaa
);
809 ok(ret
, "GetAce failed with error %u\n", GetLastError());
810 ok(paaa
->Header
.AceType
== ACCESS_DENIED_ACE_TYPE
,
811 "Invalid ACE type %d\n", paaa
->Header
.AceType
);
812 /* second ACE - with inheritance */
813 ok(paaa
->Header
.AceFlags
== MY_INHERITANCE
,
814 "Invalid ACE flags %x\n", paaa
->Header
.AceFlags
);
815 ok(paaa
->Mask
== GENERIC_READ
, "Invalid ACE mask %x\n", paaa
->Mask
);
824 static void test_SHPackDispParams(void)
830 if(!pSHPackDispParams
)
831 win_skip("SHPackSidpParams not available\n");
833 memset(¶ms
, 0xc0, sizeof(params
));
834 memset(vars
, 0xc0, sizeof(vars
));
835 hres
= pSHPackDispParams(¶ms
, vars
, 1, VT_I4
, 0xdeadbeef);
836 ok(hres
== S_OK
, "SHPackDispParams failed: %08x\n", hres
);
837 ok(params
.cArgs
== 1, "params.cArgs = %d\n", params
.cArgs
);
838 ok(params
.cNamedArgs
== 0, "params.cNamedArgs = %d\n", params
.cArgs
);
839 ok(params
.rgdispidNamedArgs
== NULL
, "params.rgdispidNamedArgs = %p\n", params
.rgdispidNamedArgs
);
840 ok(params
.rgvarg
== vars
, "params.rgvarg = %p\n", params
.rgvarg
);
841 ok(V_VT(vars
) == VT_I4
, "V_VT(var) = %d\n", V_VT(vars
));
842 ok(V_I4(vars
) == 0xdeadbeef, "failed %x\n", V_I4(vars
));
844 memset(¶ms
, 0xc0, sizeof(params
));
845 hres
= pSHPackDispParams(¶ms
, NULL
, 0, 0);
846 ok(hres
== S_OK
, "SHPackDispParams failed: %08x\n", hres
);
847 ok(params
.cArgs
== 0, "params.cArgs = %d\n", params
.cArgs
);
848 ok(params
.cNamedArgs
== 0, "params.cNamedArgs = %d\n", params
.cArgs
);
849 ok(params
.rgdispidNamedArgs
== NULL
, "params.rgdispidNamedArgs = %p\n", params
.rgdispidNamedArgs
);
850 ok(params
.rgvarg
== NULL
, "params.rgvarg = %p\n", params
.rgvarg
);
852 memset(vars
, 0xc0, sizeof(vars
));
853 memset(¶ms
, 0xc0, sizeof(params
));
854 hres
= pSHPackDispParams(¶ms
, vars
, 4, VT_BSTR
, (void*)0xdeadbeef, VT_EMPTY
, 10,
855 VT_I4
, 100, VT_DISPATCH
, (void*)0xdeadbeef);
856 ok(hres
== S_OK
, "SHPackDispParams failed: %08x\n", hres
);
857 ok(params
.cArgs
== 4, "params.cArgs = %d\n", params
.cArgs
);
858 ok(params
.cNamedArgs
== 0, "params.cNamedArgs = %d\n", params
.cArgs
);
859 ok(params
.rgdispidNamedArgs
== NULL
, "params.rgdispidNamedArgs = %p\n", params
.rgdispidNamedArgs
);
860 ok(params
.rgvarg
== vars
, "params.rgvarg = %p\n", params
.rgvarg
);
861 ok(V_VT(vars
) == VT_DISPATCH
, "V_VT(vars[0]) = %x\n", V_VT(vars
));
862 ok(V_I4(vars
) == 0xdeadbeef, "V_I4(vars[0]) = %x\n", V_I4(vars
));
863 ok(V_VT(vars
+1) == VT_I4
, "V_VT(vars[1]) = %d\n", V_VT(vars
+1));
864 ok(V_I4(vars
+1) == 100, "V_I4(vars[1]) = %x\n", V_I4(vars
+1));
865 ok(V_VT(vars
+2) == VT_I4
, "V_VT(vars[2]) = %d\n", V_VT(vars
+2));
866 ok(V_I4(vars
+2) == 10, "V_I4(vars[2]) = %x\n", V_I4(vars
+2));
867 ok(V_VT(vars
+3) == VT_BSTR
, "V_VT(vars[3]) = %d\n", V_VT(vars
+3));
868 ok(V_BSTR(vars
+3) == (void*)0xdeadbeef, "V_BSTR(vars[3]) = %p\n", V_BSTR(vars
+3));
873 IDispatch IDispatch_iface
;
877 static inline Disp
*impl_from_IDispatch(IDispatch
*iface
)
879 return CONTAINING_RECORD(iface
, Disp
, IDispatch_iface
);
882 typedef struct _contain
884 IConnectionPointContainer IConnectionPointContainer_iface
;
888 IConnectionPoint
**pt
;
891 static inline Contain
*impl_from_IConnectionPointContainer(IConnectionPointContainer
*iface
)
893 return CONTAINING_RECORD(iface
, Contain
, IConnectionPointContainer_iface
);
896 typedef struct _cntptn
898 IConnectionPoint IConnectionPoint_iface
;
907 static inline ConPt
*impl_from_IConnectionPoint(IConnectionPoint
*iface
)
909 return CONTAINING_RECORD(iface
, ConPt
, IConnectionPoint_iface
);
914 IEnumConnections IEnumConnections_iface
;
921 static inline EnumCon
*impl_from_IEnumConnections(IEnumConnections
*iface
)
923 return CONTAINING_RECORD(iface
, EnumCon
, IEnumConnections_iface
);
926 typedef struct _enumpt
928 IEnumConnectionPoints IEnumConnectionPoints_iface
;
935 static inline EnumPt
*impl_from_IEnumConnectionPoints(IEnumConnectionPoints
*iface
)
937 return CONTAINING_RECORD(iface
, EnumPt
, IEnumConnectionPoints_iface
);
941 static HRESULT WINAPI
Disp_QueryInterface(
948 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IDispatch
))
955 IDispatch_AddRef(This
);
959 trace("no interface\n");
960 return E_NOINTERFACE
;
963 static ULONG WINAPI
Disp_AddRef(IDispatch
* This
)
965 Disp
*iface
= impl_from_IDispatch(This
);
966 return InterlockedIncrement(&iface
->refCount
);
969 static ULONG WINAPI
Disp_Release(IDispatch
* This
)
971 Disp
*iface
= impl_from_IDispatch(This
);
974 ret
= InterlockedDecrement(&iface
->refCount
);
976 HeapFree(GetProcessHeap(),0,This
);
980 static HRESULT WINAPI
Disp_GetTypeInfoCount(
984 return ERROR_SUCCESS
;
987 static HRESULT WINAPI
Disp_GetTypeInfo(
993 return ERROR_SUCCESS
;
996 static HRESULT WINAPI
Disp_GetIDsOfNames(
1004 return ERROR_SUCCESS
;
1007 static HRESULT WINAPI
Disp_Invoke(
1009 DISPID dispIdMember
,
1013 DISPPARAMS
*pDispParams
,
1014 VARIANT
*pVarResult
,
1015 EXCEPINFO
*pExcepInfo
,
1018 trace("%p %x %s %x %x %p %p %p %p\n", This
, dispIdMember
, wine_dbgstr_guid(riid
), lcid
, wFlags
,
1019 pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
1021 ok(dispIdMember
== 0xa0 || dispIdMember
== 0xa1, "Unknown dispIdMember\n");
1022 ok(pDispParams
!= NULL
, "Invoked with NULL pDispParams\n");
1023 ok(wFlags
== DISPATCH_METHOD
, "Wrong flags %x\n",wFlags
);
1024 ok(lcid
== 0,"Wrong lcid %x\n",lcid
);
1025 if (dispIdMember
== 0xa0)
1027 ok(pDispParams
->cArgs
== 0, "params.cArgs = %d\n", pDispParams
->cArgs
);
1028 ok(pDispParams
->cNamedArgs
== 0, "params.cNamedArgs = %d\n", pDispParams
->cArgs
);
1029 ok(pDispParams
->rgdispidNamedArgs
== NULL
, "params.rgdispidNamedArgs = %p\n", pDispParams
->rgdispidNamedArgs
);
1030 ok(pDispParams
->rgvarg
== NULL
, "params.rgvarg = %p\n", pDispParams
->rgvarg
);
1032 else if (dispIdMember
== 0xa1)
1034 ok(pDispParams
->cArgs
== 2, "params.cArgs = %d\n", pDispParams
->cArgs
);
1035 ok(pDispParams
->cNamedArgs
== 0, "params.cNamedArgs = %d\n", pDispParams
->cArgs
);
1036 ok(pDispParams
->rgdispidNamedArgs
== NULL
, "params.rgdispidNamedArgs = %p\n", pDispParams
->rgdispidNamedArgs
);
1037 ok(V_VT(pDispParams
->rgvarg
) == VT_BSTR
, "V_VT(var) = %d\n", V_VT(pDispParams
->rgvarg
));
1038 ok(V_I4(pDispParams
->rgvarg
) == 0xdeadcafe , "failed %p\n", V_BSTR(pDispParams
->rgvarg
));
1039 ok(V_VT(pDispParams
->rgvarg
+1) == VT_I4
, "V_VT(var) = %d\n", V_VT(pDispParams
->rgvarg
+1));
1040 ok(V_I4(pDispParams
->rgvarg
+1) == 0xdeadbeef, "failed %x\n", V_I4(pDispParams
->rgvarg
+1));
1043 return ERROR_SUCCESS
;
1046 static const IDispatchVtbl disp_vtbl
= {
1047 Disp_QueryInterface
,
1051 Disp_GetTypeInfoCount
,
1057 static HRESULT WINAPI
Enum_QueryInterface(
1058 IEnumConnections
* This
,
1064 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IEnumConnections
))
1071 IEnumConnections_AddRef(This
);
1075 trace("no interface\n");
1076 return E_NOINTERFACE
;
1079 static ULONG WINAPI
Enum_AddRef(IEnumConnections
* This
)
1081 EnumCon
*iface
= impl_from_IEnumConnections(This
);
1082 return InterlockedIncrement(&iface
->refCount
);
1085 static ULONG WINAPI
Enum_Release(IEnumConnections
* This
)
1087 EnumCon
*iface
= impl_from_IEnumConnections(This
);
1090 ret
= InterlockedDecrement(&iface
->refCount
);
1092 HeapFree(GetProcessHeap(),0,This
);
1096 static HRESULT WINAPI
Enum_Next(
1097 IEnumConnections
* This
,
1102 EnumCon
*iface
= impl_from_IEnumConnections(This
);
1104 if (cConnections
> 0 && iface
->idx
< iface
->pt
->sinkCount
)
1106 rgcd
->pUnk
= iface
->pt
->sink
[iface
->idx
];
1107 IUnknown_AddRef(iface
->pt
->sink
[iface
->idx
]);
1108 rgcd
->dwCookie
=0xff;
1118 static HRESULT WINAPI
Enum_Skip(
1119 IEnumConnections
* This
,
1125 static HRESULT WINAPI
Enum_Reset(
1126 IEnumConnections
* This
)
1131 static HRESULT WINAPI
Enum_Clone(
1132 IEnumConnections
* This
,
1133 IEnumConnections
**ppEnum
)
1138 static const IEnumConnectionsVtbl enum_vtbl
= {
1140 Enum_QueryInterface
,
1149 static HRESULT WINAPI
ConPt_QueryInterface(
1150 IConnectionPoint
* This
,
1156 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IConnectionPoint
))
1163 IConnectionPoint_AddRef(This
);
1167 trace("no interface\n");
1168 return E_NOINTERFACE
;
1171 static ULONG WINAPI
ConPt_AddRef(
1172 IConnectionPoint
* This
)
1174 ConPt
*iface
= impl_from_IConnectionPoint(This
);
1175 return InterlockedIncrement(&iface
->refCount
);
1178 static ULONG WINAPI
ConPt_Release(
1179 IConnectionPoint
* This
)
1181 ConPt
*iface
= impl_from_IConnectionPoint(This
);
1184 ret
= InterlockedDecrement(&iface
->refCount
);
1187 if (iface
->sinkCount
> 0)
1190 for (i
= 0; i
< iface
->sinkCount
; i
++)
1193 IUnknown_Release(iface
->sink
[i
]);
1195 HeapFree(GetProcessHeap(),0,iface
->sink
);
1197 HeapFree(GetProcessHeap(),0,This
);
1202 static HRESULT WINAPI
ConPt_GetConnectionInterface(
1203 IConnectionPoint
* This
,
1207 ConPt
*iface
= impl_from_IConnectionPoint(This
);
1214 memcpy(pIID
,&iface
->id
,sizeof(GUID
));
1218 static HRESULT WINAPI
ConPt_GetConnectionPointContainer(
1219 IConnectionPoint
* This
,
1220 IConnectionPointContainer
**ppCPC
)
1222 ConPt
*iface
= impl_from_IConnectionPoint(This
);
1224 *ppCPC
= &iface
->container
->IConnectionPointContainer_iface
;
1228 static HRESULT WINAPI
ConPt_Advise(
1229 IConnectionPoint
* This
,
1233 ConPt
*iface
= impl_from_IConnectionPoint(This
);
1235 if (iface
->sinkCount
== 0)
1236 iface
->sink
= HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown
*));
1238 iface
->sink
= HeapReAlloc(GetProcessHeap(),0,iface
->sink
,sizeof(IUnknown
*)*(iface
->sinkCount
+1));
1239 iface
->sink
[iface
->sinkCount
] = pUnkSink
;
1240 IUnknown_AddRef(pUnkSink
);
1242 *pdwCookie
= iface
->sinkCount
;
1246 static HRESULT WINAPI
ConPt_Unadvise(
1247 IConnectionPoint
* This
,
1250 ConPt
*iface
= impl_from_IConnectionPoint(This
);
1252 if (dwCookie
> iface
->sinkCount
)
1256 IUnknown_Release(iface
->sink
[dwCookie
-1]);
1257 iface
->sink
[dwCookie
-1] = NULL
;
1262 static HRESULT WINAPI
ConPt_EnumConnections(
1263 IConnectionPoint
* This
,
1264 IEnumConnections
**ppEnum
)
1268 ec
= HeapAlloc(GetProcessHeap(),0,sizeof(EnumCon
));
1269 ec
->IEnumConnections_iface
.lpVtbl
= &enum_vtbl
;
1271 ec
->pt
= impl_from_IConnectionPoint(This
);
1273 *ppEnum
= &ec
->IEnumConnections_iface
;
1278 static const IConnectionPointVtbl point_vtbl
= {
1279 ConPt_QueryInterface
,
1283 ConPt_GetConnectionInterface
,
1284 ConPt_GetConnectionPointContainer
,
1287 ConPt_EnumConnections
1290 static HRESULT WINAPI
EnumPt_QueryInterface(
1291 IEnumConnectionPoints
* This
,
1297 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IEnumConnectionPoints
))
1304 IEnumConnectionPoints_AddRef(This
);
1308 trace("no interface\n");
1309 return E_NOINTERFACE
;
1312 static ULONG WINAPI
EnumPt_AddRef(IEnumConnectionPoints
* This
)
1314 EnumPt
*iface
= impl_from_IEnumConnectionPoints(This
);
1315 return InterlockedIncrement(&iface
->refCount
);
1318 static ULONG WINAPI
EnumPt_Release(IEnumConnectionPoints
* This
)
1320 EnumPt
*iface
= impl_from_IEnumConnectionPoints(This
);
1323 ret
= InterlockedDecrement(&iface
->refCount
);
1325 HeapFree(GetProcessHeap(),0,This
);
1329 static HRESULT WINAPI
EnumPt_Next(
1330 IEnumConnectionPoints
* This
,
1332 IConnectionPoint
**rgcd
,
1335 EnumPt
*iface
= impl_from_IEnumConnectionPoints(This
);
1337 if (cConnections
> 0 && iface
->idx
< iface
->container
->ptCount
)
1339 *rgcd
= iface
->container
->pt
[iface
->idx
];
1340 IConnectionPoint_AddRef(iface
->container
->pt
[iface
->idx
]);
1350 static HRESULT WINAPI
EnumPt_Skip(
1351 IEnumConnectionPoints
* This
,
1357 static HRESULT WINAPI
EnumPt_Reset(
1358 IEnumConnectionPoints
* This
)
1363 static HRESULT WINAPI
EnumPt_Clone(
1364 IEnumConnectionPoints
* This
,
1365 IEnumConnectionPoints
**ppEnumPt
)
1370 static const IEnumConnectionPointsVtbl enumpt_vtbl
= {
1372 EnumPt_QueryInterface
,
1381 static HRESULT WINAPI
Contain_QueryInterface(
1382 IConnectionPointContainer
* This
,
1388 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IConnectionPointContainer
))
1395 IConnectionPointContainer_AddRef(This
);
1399 trace("no interface\n");
1400 return E_NOINTERFACE
;
1403 static ULONG WINAPI
Contain_AddRef(
1404 IConnectionPointContainer
* This
)
1406 Contain
*iface
= impl_from_IConnectionPointContainer(This
);
1407 return InterlockedIncrement(&iface
->refCount
);
1410 static ULONG WINAPI
Contain_Release(
1411 IConnectionPointContainer
* This
)
1413 Contain
*iface
= impl_from_IConnectionPointContainer(This
);
1416 ret
= InterlockedDecrement(&iface
->refCount
);
1419 if (iface
->ptCount
> 0)
1422 for (i
= 0; i
< iface
->ptCount
; i
++)
1423 IConnectionPoint_Release(iface
->pt
[i
]);
1424 HeapFree(GetProcessHeap(),0,iface
->pt
);
1426 HeapFree(GetProcessHeap(),0,This
);
1431 static HRESULT WINAPI
Contain_EnumConnectionPoints(
1432 IConnectionPointContainer
* This
,
1433 IEnumConnectionPoints
**ppEnum
)
1437 ec
= HeapAlloc(GetProcessHeap(),0,sizeof(EnumPt
));
1438 ec
->IEnumConnectionPoints_iface
.lpVtbl
= &enumpt_vtbl
;
1441 ec
->container
= impl_from_IConnectionPointContainer(This
);
1442 *ppEnum
= &ec
->IEnumConnectionPoints_iface
;
1447 static HRESULT WINAPI
Contain_FindConnectionPoint(
1448 IConnectionPointContainer
* This
,
1450 IConnectionPoint
**ppCP
)
1452 Contain
*iface
= impl_from_IConnectionPointContainer(This
);
1455 if (!IsEqualIID(riid
, &IID_NULL
) || iface
->ptCount
==0)
1457 pt
= HeapAlloc(GetProcessHeap(),0,sizeof(ConPt
));
1458 pt
->IConnectionPoint_iface
.lpVtbl
= &point_vtbl
;
1462 pt
->container
= iface
;
1463 pt
->id
= IID_IDispatch
;
1465 if (iface
->ptCount
== 0)
1466 iface
->pt
=HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown
*));
1468 iface
->pt
= HeapReAlloc(GetProcessHeap(),0,iface
->pt
,sizeof(IUnknown
*)*(iface
->ptCount
+1));
1469 iface
->pt
[iface
->ptCount
] = &pt
->IConnectionPoint_iface
;
1472 *ppCP
= &pt
->IConnectionPoint_iface
;
1476 *ppCP
= iface
->pt
[0];
1477 IUnknown_AddRef((IUnknown
*)*ppCP
);
1483 static const IConnectionPointContainerVtbl contain_vtbl
= {
1484 Contain_QueryInterface
,
1488 Contain_EnumConnectionPoints
,
1489 Contain_FindConnectionPoint
1492 static void test_IConnectionPoint(void)
1496 IConnectionPoint
*point
;
1499 DWORD cookie
= 0xffffffff;
1503 if (!pIConnectionPoint_SimpleInvoke
|| !pConnectToConnectionPoint
)
1505 win_skip("IConnectionPoint Apis not present\n");
1509 container
= HeapAlloc(GetProcessHeap(),0,sizeof(Contain
));
1510 container
->IConnectionPointContainer_iface
.lpVtbl
= &contain_vtbl
;
1511 container
->refCount
= 1;
1512 container
->ptCount
= 0;
1513 container
->pt
= NULL
;
1515 dispatch
= HeapAlloc(GetProcessHeap(),0,sizeof(Disp
));
1516 dispatch
->IDispatch_iface
.lpVtbl
= &disp_vtbl
;
1517 dispatch
->refCount
= 1;
1519 rc
= pConnectToConnectionPoint((IUnknown
*)dispatch
, &IID_NULL
, TRUE
, (IUnknown
*)container
, &cookie
, &point
);
1520 ok(rc
== S_OK
, "pConnectToConnectionPoint failed with %x\n",rc
);
1521 ok(point
!= NULL
, "returned ConnectionPoint is NULL\n");
1522 ok(cookie
!= 0xffffffff, "invalid cookie returned\n");
1524 rc
= pIConnectionPoint_SimpleInvoke(point
,0xa0,NULL
);
1525 ok(rc
== S_OK
, "pConnectToConnectionPoint failed with %x\n",rc
);
1527 if (pSHPackDispParams
)
1529 memset(¶ms
, 0xc0, sizeof(params
));
1530 memset(vars
, 0xc0, sizeof(vars
));
1531 rc
= pSHPackDispParams(¶ms
, vars
, 2, VT_I4
, 0xdeadbeef, VT_BSTR
, 0xdeadcafe);
1532 ok(rc
== S_OK
, "SHPackDispParams failed: %08x\n", rc
);
1534 rc
= pIConnectionPoint_SimpleInvoke(point
,0xa1,¶ms
);
1535 ok(rc
== S_OK
, "pConnectToConnectionPoint failed with %x\n",rc
);
1538 win_skip("pSHPackDispParams not present\n");
1540 rc
= pConnectToConnectionPoint(NULL
, &IID_NULL
, FALSE
, (IUnknown
*)container
, &cookie
, NULL
);
1541 ok(rc
== S_OK
, "pConnectToConnectionPoint failed with %x\n",rc
);
1543 /* MSDN says this should be required but it crashs on XP
1544 IUnknown_Release(point);
1546 ref
= IUnknown_Release((IUnknown
*)container
);
1547 ok(ref
== 0, "leftover IConnectionPointContainer reference %i\n",ref
);
1548 ref
= IUnknown_Release((IUnknown
*)dispatch
);
1549 ok(ref
== 0, "leftover IDispatch reference %i\n",ref
);
1552 typedef struct _propbag
1554 IPropertyBag IPropertyBag_iface
;
1559 static inline PropBag
*impl_from_IPropertyBag(IPropertyBag
*iface
)
1561 return CONTAINING_RECORD(iface
, PropBag
, IPropertyBag_iface
);
1565 static HRESULT WINAPI
Prop_QueryInterface(
1572 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IPropertyBag
))
1579 IPropertyBag_AddRef(This
);
1583 trace("no interface\n");
1584 return E_NOINTERFACE
;
1587 static ULONG WINAPI
Prop_AddRef(
1590 PropBag
*iface
= impl_from_IPropertyBag(This
);
1591 return InterlockedIncrement(&iface
->refCount
);
1594 static ULONG WINAPI
Prop_Release(
1597 PropBag
*iface
= impl_from_IPropertyBag(This
);
1600 ret
= InterlockedDecrement(&iface
->refCount
);
1602 HeapFree(GetProcessHeap(),0,This
);
1606 static HRESULT WINAPI
Prop_Read(
1608 LPCOLESTR pszPropName
,
1610 IErrorLog
*pErrorLog
)
1612 V_VT(pVar
) = VT_BLOB
|VT_BYREF
;
1613 V_BYREF(pVar
) = (LPVOID
)0xdeadcafe;
1617 static HRESULT WINAPI
Prop_Write(
1619 LPCOLESTR pszPropName
,
1626 static const IPropertyBagVtbl prop_vtbl
= {
1627 Prop_QueryInterface
,
1635 static void test_SHPropertyBag_ReadLONG(void)
1640 static const WCHAR szName1
[] = {'n','a','m','e','1',0};
1642 if (!pSHPropertyBag_ReadLONG
)
1644 win_skip("SHPropertyBag_ReadLONG not present\n");
1648 pb
= HeapAlloc(GetProcessHeap(),0,sizeof(PropBag
));
1650 pb
->IPropertyBag_iface
.lpVtbl
= &prop_vtbl
;
1653 rc
= pSHPropertyBag_ReadLONG(NULL
, szName1
, &out
);
1654 ok(rc
== E_INVALIDARG
|| broken(rc
== S_OK
), "incorrect return %x\n",rc
);
1655 ok(out
== 0xfeedface, "value should not have changed\n");
1656 rc
= pSHPropertyBag_ReadLONG(&pb
->IPropertyBag_iface
, NULL
, &out
);
1657 ok(rc
== E_INVALIDARG
|| broken(rc
== S_OK
) || broken(rc
== S_FALSE
), "incorrect return %x\n",rc
);
1658 ok(out
== 0xfeedface, "value should not have changed\n");
1659 rc
= pSHPropertyBag_ReadLONG(&pb
->IPropertyBag_iface
, szName1
, NULL
);
1660 ok(rc
== E_INVALIDARG
|| broken(rc
== S_OK
) || broken(rc
== S_FALSE
), "incorrect return %x\n",rc
);
1661 rc
= pSHPropertyBag_ReadLONG(&pb
->IPropertyBag_iface
, szName1
, &out
);
1662 ok(rc
== DISP_E_BADVARTYPE
|| broken(rc
== S_OK
) || broken(rc
== S_FALSE
), "incorrect return %x\n",rc
);
1663 ok(out
== 0xfeedface || broken(out
== 0xfeedfa00), "value should not have changed %x\n",out
);
1664 IUnknown_Release((IUnknown
*)pb
);
1667 static void test_SHSetWindowBits(void)
1670 DWORD style
, styleold
;
1673 if(!pSHSetWindowBits
)
1675 win_skip("SHSetWindowBits is not available\n");
1680 clsA
.lpfnWndProc
= DefWindowProcA
;
1681 clsA
.cbClsExtra
= 0;
1682 clsA
.cbWndExtra
= 0;
1683 clsA
.hInstance
= GetModuleHandleA(NULL
);
1685 clsA
.hCursor
= LoadCursorA(0, (LPSTR
)IDC_ARROW
);
1686 clsA
.hbrBackground
= NULL
;
1687 clsA
.lpszMenuName
= NULL
;
1688 clsA
.lpszClassName
= "Shlwapi test class";
1689 RegisterClassA(&clsA
);
1691 hwnd
= CreateWindowA("Shlwapi test class", "Test", WS_VISIBLE
, 0, 0, 100, 100,
1692 NULL
, NULL
, GetModuleHandleA(NULL
), 0);
1693 ok(IsWindow(hwnd
), "failed to create window\n");
1696 SetLastError(0xdeadbeef);
1697 style
= pSHSetWindowBits(NULL
, GWL_STYLE
, 0, 0);
1698 ok(style
== 0, "expected 0 retval, got %d\n", style
);
1699 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE
||
1700 broken(GetLastError() == 0xdeadbeef), /* Win9x/WinMe */
1701 "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
1703 /* zero mask, zero flags */
1704 styleold
= GetWindowLongA(hwnd
, GWL_STYLE
);
1705 style
= pSHSetWindowBits(hwnd
, GWL_STYLE
, 0, 0);
1706 ok(styleold
== style
, "expected old style\n");
1707 ok(styleold
== GetWindowLongA(hwnd
, GWL_STYLE
), "expected to keep old style\n");
1710 styleold
= GetWindowLongA(hwnd
, GWL_STYLE
);
1711 ok(styleold
& WS_VISIBLE
, "expected WS_VISIBLE\n");
1712 style
= pSHSetWindowBits(hwnd
, GWL_STYLE
, WS_VISIBLE
, 0);
1714 ok(style
== styleold
, "expected previous style, got %x\n", style
);
1715 ok((GetWindowLongA(hwnd
, GWL_STYLE
) & WS_VISIBLE
) == 0, "expected updated style\n");
1717 /* test mask, unset style bit used */
1718 styleold
= GetWindowLongA(hwnd
, GWL_STYLE
);
1719 style
= pSHSetWindowBits(hwnd
, GWL_STYLE
, WS_VISIBLE
, 0);
1720 ok(style
== styleold
, "expected previous style, got %x\n", style
);
1721 ok(styleold
== GetWindowLongA(hwnd
, GWL_STYLE
), "expected to keep old style\n");
1723 /* set back with flags */
1724 styleold
= GetWindowLongA(hwnd
, GWL_STYLE
);
1725 style
= pSHSetWindowBits(hwnd
, GWL_STYLE
, WS_VISIBLE
, WS_VISIBLE
);
1726 ok(style
== styleold
, "expected previous style, got %x\n", style
);
1727 ok(GetWindowLongA(hwnd
, GWL_STYLE
) & WS_VISIBLE
, "expected updated style\n");
1729 /* reset and try to set without a mask */
1730 pSHSetWindowBits(hwnd
, GWL_STYLE
, WS_VISIBLE
, 0);
1731 ok((GetWindowLongA(hwnd
, GWL_STYLE
) & WS_VISIBLE
) == 0, "expected updated style\n");
1732 styleold
= GetWindowLongA(hwnd
, GWL_STYLE
);
1733 style
= pSHSetWindowBits(hwnd
, GWL_STYLE
, 0, WS_VISIBLE
);
1734 ok(style
== styleold
, "expected previous style, got %x\n", style
);
1735 ok((GetWindowLongA(hwnd
, GWL_STYLE
) & WS_VISIBLE
) == 0, "expected updated style\n");
1737 DestroyWindow(hwnd
);
1739 UnregisterClassA("Shlwapi test class", GetModuleHandleA(NULL
));
1742 static void test_SHFormatDateTimeA(void)
1744 FILETIME UNALIGNED filetime
;
1745 CHAR buff
[100], buff2
[100], buff3
[100];
1750 if(!pSHFormatDateTimeA
)
1752 win_skip("pSHFormatDateTimeA isn't available\n");
1758 /* crashes on native */
1759 pSHFormatDateTimeA(NULL
, NULL
, NULL
, 0);
1763 SystemTimeToFileTime(&st
, &filetime
);
1764 /* SHFormatDateTime expects input as utc */
1765 LocalFileTimeToFileTime(&filetime
, &filetime
);
1767 /* no way to get required buffer length here */
1768 SetLastError(0xdeadbeef);
1769 ret
= pSHFormatDateTimeA(&filetime
, NULL
, NULL
, 0);
1770 ok(ret
== 0, "got %d\n", ret
);
1771 ok(GetLastError() == 0xdeadbeef || broken(GetLastError() == ERROR_SUCCESS
/* Win7 */),
1772 "expected 0xdeadbeef, got %d\n", GetLastError());
1774 SetLastError(0xdeadbeef);
1775 buff
[0] = 'a'; buff
[1] = 0;
1776 ret
= pSHFormatDateTimeA(&filetime
, NULL
, buff
, 0);
1777 ok(ret
== 0, "got %d\n", ret
);
1778 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1779 ok(buff
[0] == 'a', "expected same string, got %s\n", buff
);
1781 /* flags needs to have FDTF_NOAUTOREADINGORDER for these tests to succeed on Vista+ */
1783 /* all combinations documented as invalid succeeded */
1784 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_SHORTTIME
| FDTF_LONGTIME
;
1785 SetLastError(0xdeadbeef);
1786 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1787 ok(ret
== lstrlenA(buff
)+1, "got %d\n", ret
);
1788 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1790 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_SHORTDATE
| FDTF_LONGDATE
;
1791 SetLastError(0xdeadbeef);
1792 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1793 ok(ret
== lstrlenA(buff
)+1, "got %d\n", ret
);
1794 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1796 flags
= FDTF_SHORTDATE
| FDTF_LTRDATE
| FDTF_RTLDATE
;
1797 SetLastError(0xdeadbeef);
1798 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1799 ok(ret
== lstrlenA(buff
)+1, "got %d\n", ret
);
1800 ok(GetLastError() == 0xdeadbeef ||
1801 broken(GetLastError() == ERROR_INVALID_FLAGS
), /* Win9x/WinMe */
1802 "expected 0xdeadbeef, got %d\n", GetLastError());
1804 /* now check returned strings */
1805 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_SHORTTIME
;
1806 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1807 ok(ret
== lstrlenA(buff
)+1, "got %d\n", ret
);
1808 ret
= GetTimeFormatA(LOCALE_USER_DEFAULT
, TIME_NOSECONDS
, &st
, NULL
, buff2
, sizeof(buff2
));
1809 ok(ret
== lstrlenA(buff2
)+1, "got %d\n", ret
);
1810 ok(lstrcmpA(buff
, buff2
) == 0, "expected (%s), got (%s)\n", buff2
, buff
);
1812 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_LONGTIME
;
1813 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1814 ok(ret
== lstrlenA(buff
)+1, "got %d\n", ret
);
1815 ret
= GetTimeFormatA(LOCALE_USER_DEFAULT
, 0, &st
, NULL
, buff2
, sizeof(buff2
));
1816 ok(ret
== lstrlenA(buff2
)+1, "got %d\n", ret
);
1817 ok(lstrcmpA(buff
, buff2
) == 0, "expected (%s), got (%s)\n", buff2
, buff
);
1819 /* both time flags */
1820 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_LONGTIME
| FDTF_SHORTTIME
;
1821 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1822 ok(ret
== lstrlenA(buff
)+1, "got %d\n", ret
);
1823 ret
= GetTimeFormatA(LOCALE_USER_DEFAULT
, 0, &st
, NULL
, buff2
, sizeof(buff2
));
1824 ok(ret
== lstrlenA(buff2
)+1, "got %d\n", ret
);
1825 ok(lstrcmpA(buff
, buff2
) == 0, "expected (%s), got (%s)\n", buff2
, buff
);
1827 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_SHORTDATE
;
1828 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1829 ok(ret
== lstrlenA(buff
)+1, "got %d\n", ret
);
1830 ret
= GetDateFormatA(LOCALE_USER_DEFAULT
, DATE_SHORTDATE
, &st
, NULL
, buff2
, sizeof(buff2
));
1831 ok(ret
== lstrlenA(buff2
)+1, "got %d\n", ret
);
1832 ok(lstrcmpA(buff
, buff2
) == 0, "expected (%s), got (%s)\n", buff2
, buff
);
1834 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_LONGDATE
;
1835 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1836 ok(ret
== lstrlenA(buff
)+1, "got %d\n", ret
);
1837 ret
= GetDateFormatA(LOCALE_USER_DEFAULT
, DATE_LONGDATE
, &st
, NULL
, buff2
, sizeof(buff2
));
1838 ok(ret
== lstrlenA(buff2
)+1, "got %d\n", ret
);
1839 ok(lstrcmpA(buff
, buff2
) == 0, "expected (%s), got (%s)\n", buff2
, buff
);
1841 /* both date flags */
1842 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_LONGDATE
| FDTF_SHORTDATE
;
1843 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1844 ok(ret
== lstrlenA(buff
)+1, "got %d\n", ret
);
1845 ret
= GetDateFormatA(LOCALE_USER_DEFAULT
, DATE_LONGDATE
, &st
, NULL
, buff2
, sizeof(buff2
));
1846 ok(ret
== lstrlenA(buff2
)+1, "got %d\n", ret
);
1847 ok(lstrcmpA(buff
, buff2
) == 0, "expected (%s), got (%s)\n", buff2
, buff
);
1849 /* various combinations of date/time flags */
1850 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_LONGDATE
| FDTF_SHORTTIME
;
1851 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1852 ok(ret
== lstrlenA(buff
)+1, "got %d, length %d\n", ret
, lstrlenA(buff
)+1);
1853 ret
= GetTimeFormatA(LOCALE_USER_DEFAULT
, TIME_NOSECONDS
, &st
, NULL
, buff3
, sizeof(buff3
));
1854 ok(ret
== lstrlenA(buff3
)+1, "got %d\n", ret
);
1855 ok(lstrcmpA(buff3
, buff
+ lstrlenA(buff
) - lstrlenA(buff3
)) == 0,
1856 "expected (%s), got (%s) for time part\n",
1857 buff3
, buff
+ lstrlenA(buff
) - lstrlenA(buff3
));
1858 ret
= GetDateFormatA(LOCALE_USER_DEFAULT
, DATE_LONGDATE
, &st
, NULL
, buff2
, sizeof(buff2
));
1859 ok(ret
== lstrlenA(buff2
)+1, "got %d\n", ret
);
1860 buff
[lstrlenA(buff2
)] = '\0';
1861 ok(lstrcmpA(buff2
, buff
) == 0, "expected (%s) got (%s) for date part\n",
1864 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_LONGDATE
| FDTF_LONGTIME
;
1865 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1866 ok(ret
== lstrlenA(buff
)+1, "got %d\n", ret
);
1867 ret
= GetTimeFormatA(LOCALE_USER_DEFAULT
, 0, &st
, NULL
, buff3
, sizeof(buff3
));
1868 ok(ret
== lstrlenA(buff3
)+1, "got %d\n", ret
);
1869 ok(lstrcmpA(buff3
, buff
+ lstrlenA(buff
) - lstrlenA(buff3
)) == 0,
1870 "expected (%s), got (%s) for time part\n",
1871 buff3
, buff
+ lstrlenA(buff
) - lstrlenA(buff3
));
1872 ret
= GetDateFormatA(LOCALE_USER_DEFAULT
, DATE_LONGDATE
, &st
, NULL
, buff2
, sizeof(buff2
));
1873 ok(ret
== lstrlenA(buff2
)+1, "got %d\n", ret
);
1874 buff
[lstrlenA(buff2
)] = '\0';
1875 ok(lstrcmpA(buff2
, buff
) == 0, "expected (%s) got (%s) for date part\n",
1878 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_SHORTDATE
| FDTF_SHORTTIME
;
1879 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1880 ok(ret
== lstrlenA(buff
)+1, "got %d\n", ret
);
1881 ret
= GetDateFormatA(LOCALE_USER_DEFAULT
, DATE_SHORTDATE
, &st
, NULL
, buff2
, sizeof(buff2
));
1882 ok(ret
== lstrlenA(buff2
)+1, "got %d\n", ret
);
1884 ret
= GetTimeFormatA(LOCALE_USER_DEFAULT
, TIME_NOSECONDS
, &st
, NULL
, buff3
, sizeof(buff3
));
1885 ok(ret
== lstrlenA(buff3
)+1, "got %d\n", ret
);
1886 strcat(buff2
, buff3
);
1887 ok(lstrcmpA(buff
, buff2
) == 0, "expected (%s), got (%s)\n", buff2
, buff
);
1889 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_SHORTDATE
| FDTF_LONGTIME
;
1890 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1891 ok(ret
== lstrlenA(buff
)+1, "got %d\n", ret
);
1892 ret
= GetDateFormatA(LOCALE_USER_DEFAULT
, DATE_SHORTDATE
, &st
, NULL
, buff2
, sizeof(buff2
));
1893 ok(ret
== lstrlenA(buff2
)+1, "got %d\n", ret
);
1895 ret
= GetTimeFormatA(LOCALE_USER_DEFAULT
, 0, &st
, NULL
, buff3
, sizeof(buff3
));
1896 ok(ret
== lstrlenA(buff3
)+1, "got %d\n", ret
);
1897 strcat(buff2
, buff3
);
1898 ok(lstrcmpA(buff
, buff2
) == 0, "expected (%s), got (%s)\n", buff2
, buff
);
1901 static void test_SHFormatDateTimeW(void)
1903 FILETIME UNALIGNED filetime
;
1904 WCHAR buff
[100], buff2
[100], buff3
[100], *p1
, *p2
;
1908 static const WCHAR spaceW
[] = {' ',0};
1909 #define UNICODE_LTR_MARK 0x200e
1910 #define UNICODE_RTL_MARK 0x200f
1912 if(!pSHFormatDateTimeW
)
1914 win_skip("pSHFormatDateTimeW isn't available\n");
1920 /* crashes on native */
1921 pSHFormatDateTimeW(NULL
, NULL
, NULL
, 0);
1925 SystemTimeToFileTime(&st
, &filetime
);
1926 /* SHFormatDateTime expects input as utc */
1927 LocalFileTimeToFileTime(&filetime
, &filetime
);
1929 /* no way to get required buffer length here */
1930 SetLastError(0xdeadbeef);
1931 ret
= pSHFormatDateTimeW(&filetime
, NULL
, NULL
, 0);
1932 ok(ret
== 0, "expected 0, got %d\n", ret
);
1933 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1935 SetLastError(0xdeadbeef);
1936 buff
[0] = 'a'; buff
[1] = 0;
1937 ret
= pSHFormatDateTimeW(&filetime
, NULL
, buff
, 0);
1938 ok(ret
== 0, "expected 0, got %d\n", ret
);
1939 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1940 ok(buff
[0] == 'a', "expected same string\n");
1942 /* all combinations documented as invalid succeeded */
1943 flags
= FDTF_SHORTTIME
| FDTF_LONGTIME
;
1944 SetLastError(0xdeadbeef);
1945 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
1946 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
1947 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
1948 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1950 flags
= FDTF_SHORTDATE
| FDTF_LONGDATE
;
1951 SetLastError(0xdeadbeef);
1952 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
1953 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
1954 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
1955 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1957 flags
= FDTF_SHORTDATE
| FDTF_LTRDATE
| FDTF_RTLDATE
;
1958 SetLastError(0xdeadbeef);
1959 buff
[0] = 0; /* NT4 doesn't clear the buffer on failure */
1960 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
1961 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
1962 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
1963 ok(GetLastError() == 0xdeadbeef ||
1964 broken(GetLastError() == ERROR_INVALID_FLAGS
), /* Win9x/WinMe/NT4 */
1965 "expected 0xdeadbeef, got %d\n", GetLastError());
1967 /* now check returned strings */
1968 flags
= FDTF_SHORTTIME
;
1969 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
1970 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
1971 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
1972 SetLastError(0xdeadbeef);
1973 ret
= GetTimeFormatW(LOCALE_USER_DEFAULT
, TIME_NOSECONDS
, &st
, NULL
, buff2
, sizeof(buff2
)/sizeof(WCHAR
));
1974 if (ret
== 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1976 win_skip("Needed W-functions are not implemented\n");
1979 ok(ret
== lstrlenW(buff2
)+1, "expected %d, got %d\n", lstrlenW(buff2
)+1, ret
);
1980 ok(lstrcmpW(buff
, buff2
) == 0, "expected equal strings\n");
1982 flags
= FDTF_LONGTIME
;
1983 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
1984 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
1985 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
1986 ret
= GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, &st
, NULL
, buff2
, sizeof(buff2
)/sizeof(WCHAR
));
1987 ok(ret
== lstrlenW(buff2
)+1, "expected %d, got %d\n", lstrlenW(buff2
)+1, ret
);
1988 ok(lstrcmpW(buff
, buff2
) == 0, "expected equal strings\n");
1990 /* both time flags */
1991 flags
= FDTF_LONGTIME
| FDTF_SHORTTIME
;
1992 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
1993 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
1994 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
1995 ret
= GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, &st
, NULL
, buff2
, sizeof(buff2
)/sizeof(WCHAR
));
1996 ok(ret
== lstrlenW(buff2
)+1, "expected %d, got %d\n", lstrlenW(buff2
)+1, ret
);
1997 ok(lstrcmpW(buff
, buff2
) == 0, "expected equal string\n");
1999 flags
= FDTF_SHORTDATE
;
2000 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
2001 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
2002 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
2003 ret
= GetDateFormatW(LOCALE_USER_DEFAULT
, DATE_SHORTDATE
, &st
, NULL
, buff2
, sizeof(buff2
)/sizeof(WCHAR
));
2004 ok(ret
== lstrlenW(buff2
)+1, "expected %d, got %d\n", lstrlenW(buff2
)+1, ret
);
2005 ok(lstrcmpW(buff
, buff2
) == 0, "expected equal strings\n");
2007 flags
= FDTF_LONGDATE
;
2008 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
2009 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
2010 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
2011 ret
= GetDateFormatW(LOCALE_USER_DEFAULT
, DATE_LONGDATE
, &st
, NULL
, buff2
, sizeof(buff2
)/sizeof(WCHAR
));
2012 ok(ret
== lstrlenW(buff2
)+1, "expected %d, got %d\n", lstrlenW(buff2
)+1, ret
);
2013 ok(lstrcmpW(buff
, buff2
) == 0, "expected equal strings\n");
2015 /* both date flags */
2016 flags
= FDTF_LONGDATE
| FDTF_SHORTDATE
;
2017 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
2018 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
2019 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
2020 ret
= GetDateFormatW(LOCALE_USER_DEFAULT
, DATE_LONGDATE
, &st
, NULL
, buff2
, sizeof(buff2
)/sizeof(WCHAR
));
2021 ok(ret
== lstrlenW(buff2
)+1, "expected %d, got %d\n", lstrlenW(buff2
)+1, ret
);
2022 ok(lstrcmpW(buff
, buff2
) == 0, "expected equal strings\n");
2024 /* various combinations of date/time flags */
2025 flags
= FDTF_LONGDATE
| FDTF_SHORTTIME
;
2026 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
2027 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
2028 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
2029 ret
= GetTimeFormatW(LOCALE_USER_DEFAULT
, TIME_NOSECONDS
, &st
, NULL
, buff3
, sizeof(buff3
)/sizeof(WCHAR
));
2030 ok(ret
== lstrlenW(buff3
)+1, "expected %d, got %d\n", lstrlenW(buff3
)+1, ret
);
2031 ok(lstrcmpW(buff3
, buff
+ lstrlenW(buff
) - lstrlenW(buff3
)) == 0,
2032 "expected (%s), got (%s) for time part\n",
2033 wine_dbgstr_w(buff3
), wine_dbgstr_w(buff
+ lstrlenW(buff
) - lstrlenW(buff3
)));
2034 ret
= GetDateFormatW(LOCALE_USER_DEFAULT
, DATE_LONGDATE
, &st
, NULL
, buff2
, sizeof(buff2
)/sizeof(WCHAR
));
2035 ok(ret
== lstrlenW(buff2
)+1, "expected %d, got %d\n", lstrlenW(buff2
)+1, ret
);
2040 while (*p1
== UNICODE_LTR_MARK
|| *p1
== UNICODE_RTL_MARK
)
2042 while (*p2
== UNICODE_LTR_MARK
|| *p2
== UNICODE_RTL_MARK
)
2048 ok(lstrcmpW(buff2
, buff
) == 0, "expected (%s) got (%s) for date part\n",
2049 wine_dbgstr_w(buff2
), wine_dbgstr_w(buff
));
2051 flags
= FDTF_LONGDATE
| FDTF_LONGTIME
;
2052 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
2053 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
2054 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
2055 ret
= GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, &st
, NULL
, buff3
, sizeof(buff3
)/sizeof(WCHAR
));
2056 ok(ret
== lstrlenW(buff3
)+1, "expected %d, got %d\n", lstrlenW(buff3
)+1, ret
);
2057 ok(lstrcmpW(buff3
, buff
+ lstrlenW(buff
) - lstrlenW(buff3
)) == 0,
2058 "expected (%s), got (%s) for time part\n",
2059 wine_dbgstr_w(buff3
), wine_dbgstr_w(buff
+ lstrlenW(buff
) - lstrlenW(buff3
)));
2060 ret
= GetDateFormatW(LOCALE_USER_DEFAULT
, DATE_LONGDATE
, &st
, NULL
, buff2
, sizeof(buff2
)/sizeof(WCHAR
));
2061 ok(ret
== lstrlenW(buff2
)+1, "expected %d, got %d\n", lstrlenW(buff2
)+1, ret
);
2066 while (*p1
== UNICODE_LTR_MARK
|| *p1
== UNICODE_RTL_MARK
)
2068 while (*p2
== UNICODE_LTR_MARK
|| *p2
== UNICODE_RTL_MARK
)
2074 ok(lstrcmpW(buff2
, buff
) == 0, "expected (%s) got (%s) for date part\n",
2075 wine_dbgstr_w(buff2
), wine_dbgstr_w(buff
));
2077 flags
= FDTF_SHORTDATE
| FDTF_SHORTTIME
;
2078 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
2079 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
2080 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
2081 ret
= GetDateFormatW(LOCALE_USER_DEFAULT
, DATE_SHORTDATE
, &st
, NULL
, buff2
, sizeof(buff2
)/sizeof(WCHAR
));
2082 ok(ret
== lstrlenW(buff2
)+1, "expected %d, got %d\n", lstrlenW(buff2
)+1, ret
);
2083 lstrcatW(buff2
, spaceW
);
2084 ret
= GetTimeFormatW(LOCALE_USER_DEFAULT
, TIME_NOSECONDS
, &st
, NULL
, buff3
, sizeof(buff3
)/sizeof(WCHAR
));
2085 ok(ret
== lstrlenW(buff3
)+1, "expected %d, got %d\n", lstrlenW(buff3
)+1, ret
);
2086 lstrcatW(buff2
, buff3
);
2087 ok(lstrcmpW(buff
, buff2
) == 0, "expected equal strings\n");
2089 flags
= FDTF_SHORTDATE
| FDTF_LONGTIME
;
2090 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
2091 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
2092 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
2093 ret
= GetDateFormatW(LOCALE_USER_DEFAULT
, DATE_SHORTDATE
, &st
, NULL
, buff2
, sizeof(buff2
)/sizeof(WCHAR
));
2094 ok(ret
== lstrlenW(buff2
)+1, "expected %d, got %d\n", lstrlenW(buff2
)+1, ret
);
2095 lstrcatW(buff2
, spaceW
);
2096 ret
= GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, &st
, NULL
, buff3
, sizeof(buff3
)/sizeof(WCHAR
));
2097 ok(ret
== lstrlenW(buff3
)+1, "expected %d, got %d\n", lstrlenW(buff3
)+1, ret
);
2098 lstrcatW(buff2
, buff3
);
2099 ok(lstrcmpW(buff
, buff2
) == 0, "expected equal strings\n");
2102 static void test_SHGetObjectCompatFlags(void)
2104 struct compat_value
{
2109 struct compat_value values
[] = {
2110 { "OTNEEDSSFCACHE", 0x1 },
2111 { "NO_WEBVIEW", 0x2 },
2112 { "UNBINDABLE", 0x4 },
2114 { "NEEDSFILESYSANCESTOR", 0x10 },
2115 { "NOTAFILESYSTEM", 0x20 },
2116 { "CTXMENU_NOVERBS", 0x40 },
2117 { "CTXMENU_LIMITEDQI", 0x80 },
2118 { "COCREATESHELLFOLDERONLY", 0x100 },
2119 { "NEEDSSTORAGEANCESTOR", 0x200 },
2120 { "NOLEGACYWEBVIEW", 0x400 },
2121 { "CTXMENU_XPQCMFLAGS", 0x1000 },
2122 { "NOIPROPERTYSTORE", 0x2000 }
2125 static const char compat_path
[] = "Software\\Microsoft\\Windows\\CurrentVersion\\ShellCompatibility\\Objects";
2126 void *pColorAdjustLuma
= GetProcAddress(hShlwapi
, "ColorAdjustLuma");
2127 CHAR keyA
[39]; /* {CLSID} */
2132 if (!pSHGetObjectCompatFlags
)
2134 win_skip("SHGetObjectCompatFlags isn't available\n");
2138 if (pColorAdjustLuma
&& pColorAdjustLuma
== pSHGetObjectCompatFlags
) /* win2k */
2140 win_skip("Skipping SHGetObjectCompatFlags, same ordinal used for ColorAdjustLuma\n");
2145 ret
= pSHGetObjectCompatFlags(NULL
, NULL
);
2146 ok(ret
== 0, "got %d\n", ret
);
2148 ret
= RegOpenKeyA(HKEY_LOCAL_MACHINE
, compat_path
, &root
);
2149 if (ret
!= ERROR_SUCCESS
)
2151 skip("No compatibility class data found\n");
2155 for (i
= 0; RegEnumKeyA(root
, i
, keyA
, sizeof(keyA
)) == ERROR_SUCCESS
; i
++)
2159 if (RegOpenKeyA(root
, keyA
, &clsid_key
) == ERROR_SUCCESS
)
2162 DWORD expected
= 0, got
, length
= sizeof(valueA
);
2166 for (v
= 0; RegEnumValueA(clsid_key
, v
, valueA
, &length
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
; v
++)
2170 for (j
= 0; j
< sizeof(values
)/sizeof(struct compat_value
); j
++)
2171 if (lstrcmpA(values
[j
].nameA
, valueA
) == 0)
2173 expected
|= values
[j
].value
;
2177 length
= sizeof(valueA
);
2180 pGUIDFromStringA(keyA
, &clsid
);
2181 got
= pSHGetObjectCompatFlags(NULL
, &clsid
);
2182 ok(got
== expected
, "got 0x%08x, expected 0x%08x. Key %s\n", got
, expected
, keyA
);
2184 RegCloseKey(clsid_key
);
2192 IOleCommandTarget IOleCommandTarget_iface
;
2194 } IOleCommandTargetImpl
;
2196 static inline IOleCommandTargetImpl
*impl_from_IOleCommandTarget(IOleCommandTarget
*iface
)
2198 return CONTAINING_RECORD(iface
, IOleCommandTargetImpl
, IOleCommandTarget_iface
);
2201 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl
;
2203 static IOleCommandTarget
* IOleCommandTargetImpl_Construct(void)
2205 IOleCommandTargetImpl
*obj
;
2207 obj
= HeapAlloc(GetProcessHeap(), 0, sizeof(*obj
));
2208 obj
->IOleCommandTarget_iface
.lpVtbl
= &IOleCommandTargetImpl_Vtbl
;
2211 return &obj
->IOleCommandTarget_iface
;
2214 static HRESULT WINAPI
IOleCommandTargetImpl_QueryInterface(IOleCommandTarget
*iface
, REFIID riid
, void **ppvObj
)
2216 IOleCommandTargetImpl
*This
= impl_from_IOleCommandTarget(iface
);
2218 if (IsEqualIID(riid
, &IID_IUnknown
) ||
2219 IsEqualIID(riid
, &IID_IOleCommandTarget
))
2226 IOleCommandTarget_AddRef(iface
);
2230 return E_NOINTERFACE
;
2233 static ULONG WINAPI
IOleCommandTargetImpl_AddRef(IOleCommandTarget
*iface
)
2235 IOleCommandTargetImpl
*This
= impl_from_IOleCommandTarget(iface
);
2236 return InterlockedIncrement(&This
->ref
);
2239 static ULONG WINAPI
IOleCommandTargetImpl_Release(IOleCommandTarget
*iface
)
2241 IOleCommandTargetImpl
*This
= impl_from_IOleCommandTarget(iface
);
2242 ULONG ref
= InterlockedDecrement(&This
->ref
);
2246 HeapFree(GetProcessHeap(), 0, This
);
2252 static HRESULT WINAPI
IOleCommandTargetImpl_QueryStatus(
2253 IOleCommandTarget
*iface
, const GUID
*group
, ULONG cCmds
, OLECMD prgCmds
[], OLECMDTEXT
*pCmdText
)
2258 static HRESULT WINAPI
IOleCommandTargetImpl_Exec(
2259 IOleCommandTarget
*iface
,
2260 const GUID
*CmdGroup
,
2266 add_call(&trace_got
, 3, CmdGroup
, (void*)(DWORD_PTR
)nCmdID
, (void*)(DWORD_PTR
)nCmdexecopt
, pvaIn
, pvaOut
);
2270 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl
=
2272 IOleCommandTargetImpl_QueryInterface
,
2273 IOleCommandTargetImpl_AddRef
,
2274 IOleCommandTargetImpl_Release
,
2275 IOleCommandTargetImpl_QueryStatus
,
2276 IOleCommandTargetImpl_Exec
2280 IServiceProvider IServiceProvider_iface
;
2282 } IServiceProviderImpl
;
2284 static inline IServiceProviderImpl
*impl_from_IServiceProvider(IServiceProvider
*iface
)
2286 return CONTAINING_RECORD(iface
, IServiceProviderImpl
, IServiceProvider_iface
);
2290 IProfferService IProfferService_iface
;
2292 } IProfferServiceImpl
;
2294 static inline IProfferServiceImpl
*impl_from_IProfferService(IProfferService
*iface
)
2296 return CONTAINING_RECORD(iface
, IProfferServiceImpl
, IProfferService_iface
);
2300 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl
;
2301 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl
;
2303 static IServiceProvider
* IServiceProviderImpl_Construct(void)
2305 IServiceProviderImpl
*obj
;
2307 obj
= HeapAlloc(GetProcessHeap(), 0, sizeof(*obj
));
2308 obj
->IServiceProvider_iface
.lpVtbl
= &IServiceProviderImpl_Vtbl
;
2311 return &obj
->IServiceProvider_iface
;
2314 static IProfferService
* IProfferServiceImpl_Construct(void)
2316 IProfferServiceImpl
*obj
;
2318 obj
= HeapAlloc(GetProcessHeap(), 0, sizeof(*obj
));
2319 obj
->IProfferService_iface
.lpVtbl
= &IProfferServiceImpl_Vtbl
;
2322 return &obj
->IProfferService_iface
;
2325 static HRESULT WINAPI
IServiceProviderImpl_QueryInterface(IServiceProvider
*iface
, REFIID riid
, void **ppvObj
)
2327 IServiceProviderImpl
*This
= impl_from_IServiceProvider(iface
);
2329 if (IsEqualIID(riid
, &IID_IUnknown
) ||
2330 IsEqualIID(riid
, &IID_IServiceProvider
))
2337 IServiceProvider_AddRef(iface
);
2338 /* native uses redefined IID_IServiceProvider symbol, so we can't compare pointers */
2339 if (IsEqualIID(riid
, &IID_IServiceProvider
))
2340 add_call(&trace_got
, 1, iface
, &IID_IServiceProvider
, 0, 0, 0);
2344 return E_NOINTERFACE
;
2347 static ULONG WINAPI
IServiceProviderImpl_AddRef(IServiceProvider
*iface
)
2349 IServiceProviderImpl
*This
= impl_from_IServiceProvider(iface
);
2350 return InterlockedIncrement(&This
->ref
);
2353 static ULONG WINAPI
IServiceProviderImpl_Release(IServiceProvider
*iface
)
2355 IServiceProviderImpl
*This
= impl_from_IServiceProvider(iface
);
2356 ULONG ref
= InterlockedDecrement(&This
->ref
);
2360 HeapFree(GetProcessHeap(), 0, This
);
2366 static HRESULT WINAPI
IServiceProviderImpl_QueryService(
2367 IServiceProvider
*iface
, REFGUID service
, REFIID riid
, void **ppv
)
2369 /* native uses redefined pointer for IID_IOleCommandTarget, not one from uuid.lib */
2370 if (IsEqualIID(riid
, &IID_IOleCommandTarget
))
2372 add_call(&trace_got
, 2, iface
, service
, &IID_IOleCommandTarget
, 0, 0);
2373 *ppv
= IOleCommandTargetImpl_Construct();
2375 if (IsEqualIID(riid
, &IID_IProfferService
))
2377 if (IsEqualIID(service
, &IID_IProfferService
))
2378 add_call(&trace_got
, 2, &IID_IProfferService
, &IID_IProfferService
, 0, 0, 0);
2379 *ppv
= IProfferServiceImpl_Construct();
2384 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl
=
2386 IServiceProviderImpl_QueryInterface
,
2387 IServiceProviderImpl_AddRef
,
2388 IServiceProviderImpl_Release
,
2389 IServiceProviderImpl_QueryService
2392 static void test_IUnknown_QueryServiceExec(void)
2394 IServiceProvider
*provider
;
2395 static const GUID dummy_serviceid
= { 0xdeadbeef };
2396 static const GUID dummy_groupid
= { 0xbeefbeef };
2397 call_trace_t trace_expected
;
2400 /* on <=W2K platforms same ordinal used for another export with different
2401 prototype, so skipping using this indirect condition */
2402 if (is_win2k_and_lower
)
2404 win_skip("IUnknown_QueryServiceExec is not available\n");
2408 provider
= IServiceProviderImpl_Construct();
2410 /* null source pointer */
2411 hr
= pIUnknown_QueryServiceExec(NULL
, &dummy_serviceid
, &dummy_groupid
, 0, 0, 0, 0);
2413 hr
== E_NOTIMPL
, /* win 8 */
2414 "got 0x%08x\n", hr
);
2417 IUnknown_QueryServiceExec( ptr1, serviceid, groupid, arg1, arg2, arg3, arg4);
2418 -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &prov );
2419 -> IServiceProvider_QueryService( prov, serviceid, &IID_IOleCommandTarget, &obj );
2420 -> IOleCommandTarget_Exec( obj, groupid, arg1, arg2, arg3, arg4 );
2422 init_call_trace(&trace_expected
);
2424 add_call(&trace_expected
, 1, provider
, &IID_IServiceProvider
, 0, 0, 0);
2425 add_call(&trace_expected
, 2, provider
, &dummy_serviceid
, &IID_IOleCommandTarget
, 0, 0);
2426 add_call(&trace_expected
, 3, &dummy_groupid
, (void*)0x1, (void*)0x2, (void*)0x3, (void*)0x4);
2428 init_call_trace(&trace_got
);
2429 hr
= pIUnknown_QueryServiceExec((IUnknown
*)provider
, &dummy_serviceid
, &dummy_groupid
, 0x1, 0x2, (void*)0x3, (void*)0x4);
2430 ok(hr
== S_OK
, "got 0x%08x\n", hr
);
2432 ok_trace(&trace_expected
, &trace_got
);
2434 free_call_trace(&trace_expected
);
2435 free_call_trace(&trace_got
);
2437 IServiceProvider_Release(provider
);
2441 static HRESULT WINAPI
IProfferServiceImpl_QueryInterface(IProfferService
*iface
, REFIID riid
, void **ppvObj
)
2443 IProfferServiceImpl
*This
= impl_from_IProfferService(iface
);
2445 if (IsEqualIID(riid
, &IID_IUnknown
) ||
2446 IsEqualIID(riid
, &IID_IProfferService
))
2450 else if (IsEqualIID(riid
, &IID_IServiceProvider
))
2452 *ppvObj
= IServiceProviderImpl_Construct();
2453 add_call(&trace_got
, 1, iface
, &IID_IServiceProvider
, 0, 0, 0);
2459 IProfferService_AddRef(iface
);
2463 return E_NOINTERFACE
;
2466 static ULONG WINAPI
IProfferServiceImpl_AddRef(IProfferService
*iface
)
2468 IProfferServiceImpl
*This
= impl_from_IProfferService(iface
);
2469 return InterlockedIncrement(&This
->ref
);
2472 static ULONG WINAPI
IProfferServiceImpl_Release(IProfferService
*iface
)
2474 IProfferServiceImpl
*This
= impl_from_IProfferService(iface
);
2475 ULONG ref
= InterlockedDecrement(&This
->ref
);
2479 HeapFree(GetProcessHeap(), 0, This
);
2485 static HRESULT WINAPI
IProfferServiceImpl_ProfferService(IProfferService
*iface
,
2486 REFGUID service
, IServiceProvider
*pService
, DWORD
*pCookie
)
2488 *pCookie
= 0xdeadbeef;
2489 add_call(&trace_got
, 3, service
, pService
, pCookie
, 0, 0);
2493 static HRESULT WINAPI
IProfferServiceImpl_RevokeService(IProfferService
*iface
, DWORD cookie
)
2495 add_call(&trace_got
, 4, (void*)(DWORD_PTR
)cookie
, 0, 0, 0, 0);
2499 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl
=
2501 IProfferServiceImpl_QueryInterface
,
2502 IProfferServiceImpl_AddRef
,
2503 IProfferServiceImpl_Release
,
2504 IProfferServiceImpl_ProfferService
,
2505 IProfferServiceImpl_RevokeService
2508 static void test_IUnknown_ProfferService(void)
2510 IServiceProvider
*provider
;
2511 IProfferService
*proff
;
2512 static const GUID dummy_serviceid
= { 0xdeadbeef };
2513 call_trace_t trace_expected
;
2517 /* on <=W2K platforms same ordinal used for another export with different
2518 prototype, so skipping using this indirect condition */
2519 if (is_win2k_and_lower
)
2521 win_skip("IUnknown_ProfferService is not available\n");
2525 provider
= IServiceProviderImpl_Construct();
2526 proff
= IProfferServiceImpl_Construct();
2528 /* null source pointer */
2529 hr
= pIUnknown_ProfferService(NULL
, &dummy_serviceid
, 0, 0);
2531 hr
== E_NOTIMPL
, /* win 8 */
2532 "got 0x%08x\n", hr
);
2535 IUnknown_ProfferService( ptr1, serviceid, arg1, arg2);
2536 -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &provider );
2537 -> IServiceProvider_QueryService( provider, &IID_IProfferService, &IID_IProfferService, &proffer );
2539 if (service pointer not null):
2540 -> IProfferService_ProfferService( proffer, serviceid, arg1, arg2 );
2542 -> IProfferService_RevokeService( proffer, *arg2 );
2544 init_call_trace(&trace_expected
);
2546 add_call(&trace_expected
, 1, proff
, &IID_IServiceProvider
, 0, 0, 0);
2547 add_call(&trace_expected
, 2, &IID_IProfferService
, &IID_IProfferService
, 0, 0, 0);
2548 add_call(&trace_expected
, 3, &dummy_serviceid
, provider
, &cookie
, 0, 0);
2550 init_call_trace(&trace_got
);
2552 hr
= pIUnknown_ProfferService((IUnknown
*)proff
, &dummy_serviceid
, provider
, &cookie
);
2553 ok(hr
== S_OK
, "got 0x%08x\n", hr
);
2554 ok(cookie
== 0xdeadbeef, "got %x\n", cookie
);
2556 ok_trace(&trace_expected
, &trace_got
);
2557 free_call_trace(&trace_got
);
2558 free_call_trace(&trace_expected
);
2560 /* same with ::Revoke path */
2561 init_call_trace(&trace_expected
);
2563 add_call(&trace_expected
, 1, proff
, &IID_IServiceProvider
, 0, 0, 0);
2564 add_call(&trace_expected
, 2, &IID_IProfferService
, &IID_IProfferService
, 0, 0, 0);
2565 add_call(&trace_expected
, 4, (void*)(DWORD_PTR
)cookie
, 0, 0, 0, 0);
2567 init_call_trace(&trace_got
);
2568 ok(cookie
!= 0, "got %x\n", cookie
);
2569 hr
= pIUnknown_ProfferService((IUnknown
*)proff
, &dummy_serviceid
, 0, &cookie
);
2570 ok(hr
== S_OK
, "got 0x%08x\n", hr
);
2571 ok(cookie
== 0, "got %x\n", cookie
);
2572 ok_trace(&trace_expected
, &trace_got
);
2573 free_call_trace(&trace_got
);
2574 free_call_trace(&trace_expected
);
2576 IServiceProvider_Release(provider
);
2577 IProfferService_Release(proff
);
2580 static void test_SHCreateWorkerWindowA(void)
2588 if (is_win2k_and_lower
)
2590 win_skip("SHCreateWorkerWindowA not available\n");
2594 hwnd
= pSHCreateWorkerWindowA(0, NULL
, 0, 0, 0, 0);
2595 ok(hwnd
!= 0, "expected window\n");
2597 GetClassNameA(hwnd
, classA
, 20);
2598 ok(lstrcmpA(classA
, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA
);
2600 ret
= GetWindowLongPtrA(hwnd
, 0);
2601 ok(ret
== 0, "got %ld\n", ret
);
2604 memset(&cliA
, 0, sizeof(cliA
));
2605 res
= GetClassInfoA(GetModuleHandleA("shlwapi.dll"), "WorkerA", &cliA
);
2606 ok(res
, "failed to get class info\n");
2607 ok(cliA
.style
== 0, "got 0x%08x\n", cliA
.style
);
2608 ok(cliA
.cbClsExtra
== 0, "got %d\n", cliA
.cbClsExtra
);
2609 ok(cliA
.cbWndExtra
== sizeof(LONG_PTR
), "got %d\n", cliA
.cbWndExtra
);
2610 ok(cliA
.lpszMenuName
== 0, "got %s\n", cliA
.lpszMenuName
);
2612 DestroyWindow(hwnd
);
2614 /* set extra bytes */
2615 hwnd
= pSHCreateWorkerWindowA(0, NULL
, 0, 0, 0, 0xdeadbeef);
2616 ok(hwnd
!= 0, "expected window\n");
2618 GetClassNameA(hwnd
, classA
, 20);
2619 ok(lstrcmpA(classA
, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA
);
2621 ret
= GetWindowLongPtrA(hwnd
, 0);
2622 ok(ret
== 0xdeadbeef, "got %ld\n", ret
);
2625 ret
= GetWindowLongA(hwnd
, GWL_EXSTYLE
);
2626 ok(ret
== WS_EX_WINDOWEDGE
||
2627 ret
== (WS_EX_WINDOWEDGE
|WS_EX_LAYOUTRTL
) /* systems with RTL locale */, "0x%08lx\n", ret
);
2629 DestroyWindow(hwnd
);
2631 hwnd
= pSHCreateWorkerWindowA(0, NULL
, WS_EX_TOOLWINDOW
, 0, 0, 0);
2632 ret
= GetWindowLongA(hwnd
, GWL_EXSTYLE
);
2633 ok(ret
== (WS_EX_WINDOWEDGE
|WS_EX_TOOLWINDOW
) ||
2634 ret
== (WS_EX_WINDOWEDGE
|WS_EX_TOOLWINDOW
|WS_EX_LAYOUTRTL
) /* systems with RTL locale */, "0x%08lx\n", ret
);
2635 DestroyWindow(hwnd
);
2638 static HRESULT WINAPI
SF_QueryInterface(IShellFolder
*iface
,
2639 REFIID riid
, void **ppv
)
2641 /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */
2642 ok(!IsEqualGUID(&IID_IShellFolder
, riid
),
2643 "Unexpected QI for IShellFolder\n");
2644 return E_NOINTERFACE
;
2647 static ULONG WINAPI
SF_AddRef(IShellFolder
*iface
)
2652 static ULONG WINAPI
SF_Release(IShellFolder
*iface
)
2657 static HRESULT WINAPI
SF_ParseDisplayName(IShellFolder
*iface
,
2658 HWND owner
, LPBC reserved
, LPOLESTR displayName
, ULONG
*eaten
,
2659 LPITEMIDLIST
*idl
, ULONG
*attr
)
2661 ok(0, "Didn't expect ParseDisplayName\n");
2665 static HRESULT WINAPI
SF_EnumObjects(IShellFolder
*iface
,
2666 HWND owner
, SHCONTF flags
, IEnumIDList
**enm
)
2668 *enm
= (IEnumIDList
*)0xcafebabe;
2672 static HRESULT WINAPI
SF_BindToObject(IShellFolder
*iface
,
2673 LPCITEMIDLIST idl
, LPBC reserved
, REFIID riid
, void **obj
)
2675 ok(0, "Didn't expect BindToObject\n");
2679 static HRESULT WINAPI
SF_BindToStorage(IShellFolder
*iface
,
2680 LPCITEMIDLIST idl
, LPBC reserved
, REFIID riid
, void **obj
)
2682 ok(0, "Didn't expect BindToStorage\n");
2686 static HRESULT WINAPI
SF_CompareIDs(IShellFolder
*iface
,
2687 LPARAM lparam
, LPCITEMIDLIST idl1
, LPCITEMIDLIST idl2
)
2689 ok(0, "Didn't expect CompareIDs\n");
2693 static HRESULT WINAPI
SF_CreateViewObject(IShellFolder
*iface
,
2694 HWND owner
, REFIID riid
, void **out
)
2696 ok(0, "Didn't expect CreateViewObject\n");
2700 static HRESULT WINAPI
SF_GetAttributesOf(IShellFolder
*iface
,
2702 UINT cidl
, PCUITEMID_CHILD_ARRAY idl
, SFGAOF
*inOut
)
2704 UINT cidl
, LPCITEMIDLIST
*idl
, SFGAOF
*inOut
)
2707 ok(0, "Didn't expect GetAttributesOf\n");
2711 static HRESULT WINAPI
SF_GetUIObjectOf(IShellFolder
*iface
,
2713 HWND owner
, UINT cidl
, PCUITEMID_CHILD_ARRAY idls
, REFIID riid
, UINT
*inOut
,
2715 HWND owner
, UINT cidl
, LPCITEMIDLIST
*idls
, REFIID riid
, UINT
*inOut
,
2719 ok(0, "Didn't expect GetUIObjectOf\n");
2723 static HRESULT WINAPI
SF_GetDisplayNameOf(IShellFolder
*iface
,
2724 LPCITEMIDLIST idl
, SHGDNF flags
, STRRET
*name
)
2726 ok(0, "Didn't expect GetDisplayNameOf\n");
2730 static HRESULT WINAPI
SF_SetNameOf(IShellFolder
*iface
,
2731 HWND hwnd
, LPCITEMIDLIST idl
, LPCOLESTR name
, SHGDNF flags
,
2732 LPITEMIDLIST
*idlOut
)
2734 ok(0, "Didn't expect SetNameOf\n");
2738 static IShellFolderVtbl ShellFolderVtbl
= {
2742 SF_ParseDisplayName
,
2747 SF_CreateViewObject
,
2750 SF_GetDisplayNameOf
,
2754 static IShellFolder ShellFolder
= { &ShellFolderVtbl
};
2756 static void test_SHIShellFolder_EnumObjects(void)
2760 IShellFolder
*folder
;
2762 if(!pSHIShellFolder_EnumObjects
|| is_win2k_and_lower
){
2763 win_skip("SHIShellFolder_EnumObjects not available\n");
2768 /* NULL object crashes on Windows */
2769 pSHIShellFolder_EnumObjects(NULL
, NULL
, 0, NULL
);
2772 /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */
2773 enm
= (IEnumIDList
*)0xdeadbeef;
2774 hres
= pSHIShellFolder_EnumObjects(&ShellFolder
, NULL
, 0, &enm
);
2775 ok(hres
== S_OK
, "SHIShellFolder_EnumObjects failed: 0x%08x\n", hres
);
2776 ok(enm
== (IEnumIDList
*)0xcafebabe, "Didn't get expected enumerator location, instead: %p\n", enm
);
2778 /* SHIShellFolder_EnumObjects isn't strict about the IShellFolder object */
2779 hres
= pSHGetDesktopFolder(&folder
);
2780 ok(hres
== S_OK
, "SHGetDesktopFolder failed: 0x%08x\n", hres
);
2783 hres
= pSHIShellFolder_EnumObjects(folder
, NULL
, 0, &enm
);
2784 ok(hres
== S_OK
, "SHIShellFolder_EnumObjects failed: 0x%08x\n", hres
);
2785 ok(enm
!= NULL
, "Didn't get an enumerator\n");
2787 IEnumIDList_Release(enm
);
2789 IShellFolder_Release(folder
);
2792 static BOOL
write_inifile(LPCWSTR filename
)
2797 static const char data
[] =
2800 "AnotherKey=asdf\r\n";
2802 file
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
2803 if(file
== INVALID_HANDLE_VALUE
) {
2804 win_skip("failed to create ini file at %s\n", wine_dbgstr_w(filename
));
2808 WriteFile(file
, data
, sizeof(data
), &written
, NULL
);
2815 #define verify_inifile(f, e) r_verify_inifile(__LINE__, f, e)
2816 static void r_verify_inifile(unsigned l
, LPCWSTR filename
, LPCSTR exp
)
2822 file
= CreateFileW(filename
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
2824 if(file
== INVALID_HANDLE_VALUE
)
2827 ReadFile(file
, buf
, sizeof(buf
) * sizeof(CHAR
), &read
, NULL
);
2832 ok_(__FILE__
,l
)(!strcmp(buf
, exp
), "Expected:\n%s\nGot:\n%s\n", exp
,
2836 static void test_SHGetIniString(void)
2839 WCHAR out
[64] = {0};
2841 static const WCHAR TestAppW
[] = {'T','e','s','t','A','p','p',0};
2842 static const WCHAR AKeyW
[] = {'A','K','e','y',0};
2843 static const WCHAR AnotherKeyW
[] = {'A','n','o','t','h','e','r','K','e','y',0};
2844 static const WCHAR JunkKeyW
[] = {'J','u','n','k','K','e','y',0};
2845 static const WCHAR testpathW
[] = {'C',':','\\','t','e','s','t','.','i','n','i',0};
2846 WCHAR pathW
[MAX_PATH
];
2848 if(!pSHGetIniStringW
|| is_win2k_and_lower
){
2849 win_skip("SHGetIniStringW is not available\n");
2853 lstrcpyW(pathW
, testpathW
);
2855 if (!write_inifile(pathW
))
2859 /* these crash on Windows */
2860 pSHGetIniStringW(NULL
, NULL
, NULL
, 0, NULL
);
2861 pSHGetIniStringW(NULL
, AKeyW
, out
, sizeof(out
), pathW
);
2862 pSHGetIniStringW(TestAppW
, AKeyW
, NULL
, sizeof(out
), pathW
);
2865 ret
= pSHGetIniStringW(TestAppW
, AKeyW
, out
, 0, pathW
);
2866 ok(ret
== 0, "SHGetIniStringW should have given 0, instead: %d\n", ret
);
2868 /* valid arguments */
2870 SetLastError(0xdeadbeef);
2871 ret
= pSHGetIniStringW(TestAppW
, NULL
, out
, sizeof(out
), pathW
);
2872 ok(ret
== 4, "SHGetIniStringW should have given 4, instead: %d\n", ret
);
2873 ok(!lstrcmpW(out
, AKeyW
), "Expected %s, got: %s, %d\n",
2874 wine_dbgstr_w(AKeyW
), wine_dbgstr_w(out
), GetLastError());
2876 ret
= pSHGetIniStringW(TestAppW
, AKeyW
, out
, sizeof(out
), pathW
);
2877 ok(ret
== 1, "SHGetIniStringW should have given 1, instead: %d\n", ret
);
2878 ok(!strcmp_wa(out
, "1"), "Expected L\"1\", got: %s\n", wine_dbgstr_w(out
));
2880 ret
= pSHGetIniStringW(TestAppW
, AnotherKeyW
, out
, sizeof(out
), pathW
);
2881 ok(ret
== 4, "SHGetIniStringW should have given 4, instead: %d\n", ret
);
2882 ok(!strcmp_wa(out
, "asdf"), "Expected L\"asdf\", got: %s\n", wine_dbgstr_w(out
));
2885 ret
= pSHGetIniStringW(TestAppW
, JunkKeyW
, out
, sizeof(out
), pathW
);
2886 ok(ret
== 0, "SHGetIniStringW should have given 0, instead: %d\n", ret
);
2887 ok(*out
== 0, "Expected L\"\", got: %s\n", wine_dbgstr_w(out
));
2892 static void test_SHSetIniString(void)
2896 static const WCHAR TestAppW
[] = {'T','e','s','t','A','p','p',0};
2897 static const WCHAR AnotherAppW
[] = {'A','n','o','t','h','e','r','A','p','p',0};
2898 static const WCHAR TestIniW
[] = {'C',':','\\','t','e','s','t','.','i','n','i',0};
2899 static const WCHAR AKeyW
[] = {'A','K','e','y',0};
2900 static const WCHAR NewKeyW
[] = {'N','e','w','K','e','y',0};
2901 static const WCHAR AValueW
[] = {'A','V','a','l','u','e',0};
2903 if(!pSHSetIniStringW
|| is_win2k_and_lower
){
2904 win_skip("SHSetIniStringW is not available\n");
2908 if (!write_inifile(TestIniW
))
2911 ret
= pSHSetIniStringW(TestAppW
, AKeyW
, AValueW
, TestIniW
);
2912 ok(ret
== TRUE
, "SHSetIniStringW should not have failed\n");
2913 todo_wine
/* wine sticks an extra \r\n at the end of the file */
2914 verify_inifile(TestIniW
, "[TestApp]\r\nAKey=AValue\r\nAnotherKey=asdf\r\n");
2916 ret
= pSHSetIniStringW(TestAppW
, AKeyW
, NULL
, TestIniW
);
2917 ok(ret
== TRUE
, "SHSetIniStringW should not have failed\n");
2918 verify_inifile(TestIniW
, "[TestApp]\r\nAnotherKey=asdf\r\n");
2920 ret
= pSHSetIniStringW(AnotherAppW
, NewKeyW
, AValueW
, TestIniW
);
2921 ok(ret
== TRUE
, "SHSetIniStringW should not have failed\n");
2922 verify_inifile(TestIniW
, "[TestApp]\r\nAnotherKey=asdf\r\n[AnotherApp]\r\nNewKey=AValue\r\n");
2924 ret
= pSHSetIniStringW(TestAppW
, NULL
, AValueW
, TestIniW
);
2925 ok(ret
== TRUE
, "SHSetIniStringW should not have failed\n");
2926 verify_inifile(TestIniW
, "[AnotherApp]\r\nNewKey=AValue\r\n");
2928 DeleteFileW(TestIniW
);
2931 enum _shellkey_flags
{
2932 SHKEY_Root_HKCU
= 0x1,
2933 SHKEY_Root_HKLM
= 0x2,
2934 SHKEY_Key_Explorer
= 0x00,
2935 SHKEY_Key_Shell
= 0x10,
2936 SHKEY_Key_ShellNoRoam
= 0x20,
2937 SHKEY_Key_Classes
= 0x30,
2938 SHKEY_Subkey_Default
= 0x0000,
2939 SHKEY_Subkey_ResourceName
= 0x1000,
2940 SHKEY_Subkey_Handlers
= 0x2000,
2941 SHKEY_Subkey_Associations
= 0x3000,
2942 SHKEY_Subkey_Volatile
= 0x4000,
2943 SHKEY_Subkey_MUICache
= 0x5000,
2944 SHKEY_Subkey_FileExts
= 0x6000
2947 static void test_SHGetShellKey(void)
2949 static const WCHAR ShellFoldersW
[] = { 'S','h','e','l','l',' ','F','o','l','d','e','r','s',0 };
2950 static const WCHAR WineTestW
[] = { 'W','i','n','e','T','e','s','t',0 };
2952 void *pPathBuildRootW
= GetProcAddress(hShlwapi
, "PathBuildRootW");
2953 DWORD
*alloc_data
, data
, size
;
2957 if (!pSHGetShellKey
)
2959 win_skip("SHGetShellKey(ordinal 491) isn't available\n");
2964 if (pPathBuildRootW
&& pPathBuildRootW
== pSHGetShellKey
)
2966 win_skip("SHGetShellKey(ordinal 491) used for PathBuildRootW\n");
2970 if (is_win9x
|| is_win2k_and_lower
)
2972 win_skip("Ordinal 491 used for another call, skipping SHGetShellKey tests\n");
2976 /* Vista+ limits SHKEY enumeration values */
2977 SetLastError(0xdeadbeef);
2978 hkey
= pSHGetShellKey(SHKEY_Key_Explorer
, ShellFoldersW
, FALSE
);
2981 /* Tests not working on Vista+ */
2984 hkey
= pSHGetShellKey(SHKEY_Root_HKLM
|SHKEY_Key_Classes
, NULL
, FALSE
);
2985 ok(hkey
!= NULL
, "hkey = NULL\n");
2989 hkey
= pSHGetShellKey(SHKEY_Root_HKCU
|SHKEY_Key_Explorer
, ShellFoldersW
, FALSE
);
2990 ok(hkey
!= NULL
, "hkey = NULL\n");
2993 hkey
= pSHGetShellKey(SHKEY_Root_HKLM
|SHKEY_Key_Explorer
, ShellFoldersW
, FALSE
);
2994 ok(hkey
!= NULL
, "hkey = NULL\n");
2997 hkey
= pSHGetShellKey(SHKEY_Root_HKLM
, WineTestW
, FALSE
);
2998 ok(hkey
== NULL
, "hkey != NULL\n");
3000 hkey
= pSHGetShellKey(SHKEY_Root_HKLM
, NULL
, FALSE
);
3001 ok(hkey
!= NULL
, "Can't open key\n");
3002 ok(SUCCEEDED(RegDeleteKeyW(hkey
, WineTestW
)), "Can't delete key\n");
3005 hkey
= pSHGetShellKey(SHKEY_Root_HKLM
, WineTestW
, TRUE
);
3006 if (!hkey
&& GetLastError() == ERROR_ACCESS_DENIED
)
3008 skip("Not authorized to create keys\n");
3011 ok(hkey
!= NULL
, "Can't create key\n");
3014 if (!pSKGetValueW
|| !pSKSetValueW
|| !pSKDeleteValueW
|| !pSKAllocValueW
)
3016 win_skip("SKGetValueW, SKSetValueW, SKDeleteValueW or SKAllocValueW not available\n");
3020 size
= sizeof(data
);
3021 hres
= pSKGetValueW(SHKEY_Root_HKLM
, WineTestW
, NULL
, NULL
, &data
, &size
);
3022 ok(hres
== HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
), "hres = %x\n", hres
);
3025 hres
= pSKSetValueW(SHKEY_Root_HKLM
, WineTestW
, NULL
, REG_DWORD
, &data
, sizeof(DWORD
));
3026 ok(hres
== S_OK
, "hres = %x\n", hres
);
3029 hres
= pSKGetValueW(SHKEY_Root_HKLM
, WineTestW
, NULL
, NULL
, NULL
, &size
);
3030 ok(hres
== S_OK
, "hres = %x\n", hres
);
3031 ok(size
== sizeof(DWORD
), "size = %d\n", size
);
3034 hres
= pSKGetValueW(SHKEY_Root_HKLM
, WineTestW
, NULL
, NULL
, &data
, &size
);
3035 ok(hres
== S_OK
, "hres = %x\n", hres
);
3036 ok(size
== sizeof(DWORD
), "size = %d\n", size
);
3037 ok(data
== 1234, "data = %d\n", data
);
3039 hres
= pSKAllocValueW(SHKEY_Root_HKLM
, WineTestW
, NULL
, NULL
, (void**)&alloc_data
, &size
);
3040 ok(hres
== S_OK
, "hres= %x\n", hres
);
3041 ok(size
== sizeof(DWORD
), "size = %d\n", size
);
3042 if (SUCCEEDED(hres
))
3044 ok(*alloc_data
== 1234, "*alloc_data = %d\n", *alloc_data
);
3045 LocalFree(alloc_data
);
3048 hres
= pSKDeleteValueW(SHKEY_Root_HKLM
, WineTestW
, NULL
);
3049 ok(hres
== S_OK
, "hres = %x\n", hres
);
3051 hres
= pSKDeleteValueW(SHKEY_Root_HKLM
, WineTestW
, NULL
);
3052 ok(hres
== HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
), "hres = %x\n", hres
);
3054 hres
= pSKGetValueW(SHKEY_Root_HKLM
, WineTestW
, NULL
, NULL
, &data
, &size
);
3055 ok(hres
== HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
), "hres = %x\n", hres
);
3057 hkey
= pSHGetShellKey(SHKEY_Root_HKLM
, NULL
, FALSE
);
3058 ok(hkey
!= NULL
, "Can't create key\n");
3059 ok(SUCCEEDED(RegDeleteKeyW(hkey
, WineTestW
)), "Can't delete key\n");
3063 static void init_pointers(void)
3065 #define MAKEFUNC(f, ord) (p##f = (void*)GetProcAddress(hShlwapi, (LPSTR)(ord)))
3066 MAKEFUNC(SHAllocShared
, 7);
3067 MAKEFUNC(SHLockShared
, 8);
3068 MAKEFUNC(SHUnlockShared
, 9);
3069 MAKEFUNC(SHFreeShared
, 10);
3070 MAKEFUNC(SHMapHandle
, 11);
3071 MAKEFUNC(GetAcceptLanguagesA
, 14);
3072 MAKEFUNC(SHSetWindowBits
, 165);
3073 MAKEFUNC(SHSetParentHwnd
, 167);
3074 MAKEFUNC(ConnectToConnectionPoint
, 168);
3075 MAKEFUNC(IUnknown_GetClassID
, 175);
3076 MAKEFUNC(SHSearchMapInt
, 198);
3077 MAKEFUNC(SHCreateWorkerWindowA
, 257);
3078 MAKEFUNC(GUIDFromStringA
, 269);
3079 MAKEFUNC(SHPackDispParams
, 282);
3080 MAKEFUNC(IConnectionPoint_InvokeWithCancel
, 283);
3081 MAKEFUNC(IConnectionPoint_SimpleInvoke
, 284);
3082 MAKEFUNC(SHGetIniStringW
, 294);
3083 MAKEFUNC(SHSetIniStringW
, 295);
3084 MAKEFUNC(SHFormatDateTimeA
, 353);
3085 MAKEFUNC(SHFormatDateTimeW
, 354);
3086 MAKEFUNC(SHIShellFolder_EnumObjects
, 404);
3087 MAKEFUNC(GetShellSecurityDescriptor
, 475);
3088 MAKEFUNC(SHGetObjectCompatFlags
, 476);
3089 MAKEFUNC(IUnknown_QueryServiceExec
, 484);
3090 MAKEFUNC(SHGetShellKey
, 491);
3091 MAKEFUNC(SHPropertyBag_ReadLONG
, 496);
3092 MAKEFUNC(IUnknown_ProfferService
, 514);
3093 MAKEFUNC(SKGetValueW
, 516);
3094 MAKEFUNC(SKSetValueW
, 517);
3095 MAKEFUNC(SKDeleteValueW
, 518);
3096 MAKEFUNC(SKAllocValueW
, 519);
3099 pDllGetVersion
= (void*)GetProcAddress(hShlwapi
, "DllGetVersion");
3102 static void test_SHSetParentHwnd(void)
3104 HWND hwnd
, hwnd2
, ret
;
3107 if (!pSHSetParentHwnd
)
3109 win_skip("SHSetParentHwnd not available\n");
3113 hwnd
= CreateWindowA("Button", "", WS_VISIBLE
, 0, 0, 10, 10, NULL
, NULL
, NULL
, NULL
);
3114 ok(hwnd
!= NULL
, "got %p\n", hwnd
);
3116 hwnd2
= CreateWindowA("Button", "", WS_VISIBLE
| WS_CHILD
, 0, 0, 10, 10, hwnd
, NULL
, NULL
, NULL
);
3117 ok(hwnd2
!= NULL
, "got %p\n", hwnd2
);
3120 ret
= pSHSetParentHwnd(NULL
, NULL
);
3121 ok(ret
== NULL
, "got %p\n", ret
);
3123 /* set to no parent while already no parent present */
3124 ret
= GetParent(hwnd
);
3125 ok(ret
== NULL
, "got %p\n", ret
);
3126 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
3127 ok((style
& (WS_POPUP
|WS_CHILD
)) == 0, "got style 0x%08x\n", style
);
3128 ret
= pSHSetParentHwnd(hwnd
, NULL
);
3129 ok(ret
== NULL
, "got %p\n", ret
);
3130 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
3131 ok((style
& (WS_POPUP
|WS_CHILD
)) == 0, "got style 0x%08x\n", style
);
3133 /* reset to null parent from not null */
3134 ret
= GetParent(hwnd2
);
3135 ok(ret
== hwnd
, "got %p\n", ret
);
3136 style
= GetWindowLongA(hwnd2
, GWL_STYLE
);
3137 ok((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
, "got style 0x%08x\n", style
);
3138 ret
= pSHSetParentHwnd(hwnd2
, NULL
);
3139 ok(ret
== NULL
, "got %p\n", ret
);
3140 style
= GetWindowLongA(hwnd2
, GWL_STYLE
);
3141 ok((style
& (WS_POPUP
|WS_CHILD
)) == WS_POPUP
, "got style 0x%08x\n", style
);
3142 ret
= GetParent(hwnd2
);
3143 ok(ret
== NULL
, "got %p\n", ret
);
3145 /* set parent back */
3146 style
= GetWindowLongA(hwnd2
, GWL_STYLE
);
3147 SetWindowLongA(hwnd2
, GWL_STYLE
, style
& ~(WS_CHILD
|WS_POPUP
));
3148 style
= GetWindowLongA(hwnd2
, GWL_STYLE
);
3149 ok((style
& (WS_CHILD
|WS_POPUP
)) == 0, "got 0x%08x\n", style
);
3151 ret
= pSHSetParentHwnd(hwnd2
, hwnd
);
3152 todo_wine
ok(ret
== NULL
, "got %p\n", ret
);
3154 style
= GetWindowLongA(hwnd2
, GWL_STYLE
);
3155 ok((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
, "got style 0x%08x\n", style
);
3156 ret
= GetParent(hwnd2
);
3157 ok(ret
== hwnd
, "got %p\n", ret
);
3159 /* try to set same parent again */
3161 style
= GetWindowLongA(hwnd2
, GWL_STYLE
);
3162 SetWindowLongA(hwnd2
, GWL_STYLE
, style
| WS_POPUP
);
3163 ret
= pSHSetParentHwnd(hwnd2
, hwnd
);
3164 todo_wine
ok(ret
== NULL
, "got %p\n", ret
);
3165 style
= GetWindowLongA(hwnd2
, GWL_STYLE
);
3166 ok((style
& (WS_CHILD
|WS_POPUP
)) == WS_CHILD
, "got 0x%08x\n", style
);
3167 ret
= GetParent(hwnd2
);
3168 ok(ret
== hwnd
, "got %p\n", ret
);
3170 /* without WS_POPUP */
3171 style
= GetWindowLongA(hwnd2
, GWL_STYLE
);
3172 SetWindowLongA(hwnd2
, GWL_STYLE
, style
| ~WS_POPUP
);
3173 ret
= pSHSetParentHwnd(hwnd2
, hwnd
);
3174 todo_wine
ok(ret
== hwnd
, "got %p\n", ret
);
3175 style
= GetWindowLongA(hwnd2
, GWL_STYLE
);
3176 ok((style
& (WS_CHILD
|WS_POPUP
)) == WS_CHILD
, "got 0x%08x\n", style
);
3177 ret
= GetParent(hwnd2
);
3178 ok(ret
== hwnd
, "got %p\n", ret
);
3180 DestroyWindow(hwnd
);
3181 DestroyWindow(hwnd2
);
3184 static HRESULT WINAPI
testpersist_QI(IPersist
*iface
, REFIID riid
, void **obj
)
3186 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IPersist
)) {
3188 IPersist_AddRef(iface
);
3193 return E_NOINTERFACE
;
3196 static HRESULT WINAPI
testpersist_QI2(IPersist
*iface
, REFIID riid
, void **obj
)
3198 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IPersistFolder
)) {
3200 IPersist_AddRef(iface
);
3205 return E_NOINTERFACE
;
3208 static ULONG WINAPI
testpersist_AddRef(IPersist
*iface
)
3213 static ULONG WINAPI
testpersist_Release(IPersist
*iface
)
3218 static HRESULT WINAPI
testpersist_GetClassID(IPersist
*iface
, CLSID
*clsid
)
3220 memset(clsid
, 0xab, sizeof(*clsid
));
3224 static IPersistVtbl testpersistvtbl
= {
3227 testpersist_Release
,
3228 testpersist_GetClassID
3231 static IPersistVtbl testpersist2vtbl
= {
3234 testpersist_Release
,
3235 testpersist_GetClassID
3238 static IPersist testpersist
= { &testpersistvtbl
};
3239 static IPersist testpersist2
= { &testpersist2vtbl
};
3241 static void test_IUnknown_GetClassID(void)
3243 CLSID clsid
, clsid2
, clsid3
;
3246 if (0) /* crashes on native systems */
3247 hr
= pIUnknown_GetClassID(NULL
, NULL
);
3249 memset(&clsid
, 0xcc, sizeof(clsid
));
3250 memset(&clsid3
, 0xcc, sizeof(clsid3
));
3251 hr
= pIUnknown_GetClassID(NULL
, &clsid
);
3252 ok(hr
== E_FAIL
, "got 0x%08x\n", hr
);
3253 ok(IsEqualCLSID(&clsid
, &CLSID_NULL
) || broken(IsEqualCLSID(&clsid
, &clsid3
)) /* win2k, winxp, win2k3 */,
3254 "got wrong clsid %s\n", wine_dbgstr_guid(&clsid
));
3256 memset(&clsid
, 0xcc, sizeof(clsid
));
3257 memset(&clsid2
, 0xab, sizeof(clsid2
));
3258 hr
= pIUnknown_GetClassID((IUnknown
*)&testpersist
, &clsid
);
3259 ok(hr
== 0x8fff2222, "got 0x%08x\n", hr
);
3260 ok(IsEqualCLSID(&clsid
, &clsid2
) || broken(IsEqualCLSID(&clsid
, &clsid3
)) /* win2k3 */,
3261 "got wrong clsid %s\n", wine_dbgstr_guid(&clsid
));
3263 /* IPersistFolder is also supported */
3264 memset(&clsid
, 0xcc, sizeof(clsid
));
3265 memset(&clsid2
, 0xab, sizeof(clsid2
));
3266 memset(&clsid3
, 0xcc, sizeof(clsid3
));
3267 hr
= pIUnknown_GetClassID((IUnknown
*)&testpersist2
, &clsid
);
3268 ok(hr
== 0x8fff2222, "got 0x%08x\n", hr
);
3269 ok(IsEqualCLSID(&clsid
, &clsid2
) || broken(IsEqualCLSID(&clsid
, &clsid3
)) /* win2k3 */,
3270 "got wrong clsid %s\n", wine_dbgstr_guid(&clsid
));
3273 static void test_DllGetVersion(void)
3277 hr
= pDllGetVersion(NULL
);
3278 ok(hr
== E_INVALIDARG
, "got 0x%08x\n", hr
);
3286 hShlwapi
= GetModuleHandleA("shlwapi.dll");
3287 is_win2k_and_lower
= GetProcAddress(hShlwapi
, "StrChrNW") == 0;
3288 is_win9x
= GetProcAddress(hShlwapi
, (LPSTR
)99) == 0; /* StrCpyNXA */
3290 /* SHCreateStreamOnFileEx was introduced in shlwapi v6.0 */
3291 if(!GetProcAddress(hShlwapi
, "SHCreateStreamOnFileEx")){
3292 win_skip("Too old shlwapi version\n");
3298 argc
= winetest_get_mainargs(&argv
);
3303 sscanf(argv
[2], "%d", &procid
);
3304 sscanf(argv
[3], "%p", &hmem
);
3305 test_alloc_shared_remote(procid
, hmem
);
3309 hmlang
= LoadLibraryA("mlang.dll");
3310 pLcidToRfc1766A
= (void *)GetProcAddress(hmlang
, "LcidToRfc1766A");
3312 hshell32
= LoadLibraryA("shell32.dll");
3313 pSHGetDesktopFolder
= (void *)GetProcAddress(hshell32
, "SHGetDesktopFolder");
3315 test_GetAcceptLanguagesA();
3316 test_SHSearchMapInt();
3317 test_alloc_shared(argc
, argv
);
3319 test_GetShellSecurityDescriptor();
3320 test_SHPackDispParams();
3321 test_IConnectionPoint();
3322 test_SHPropertyBag_ReadLONG();
3323 test_SHSetWindowBits();
3324 test_SHFormatDateTimeA();
3325 test_SHFormatDateTimeW();
3326 test_SHGetObjectCompatFlags();
3327 test_IUnknown_QueryServiceExec();
3328 test_IUnknown_ProfferService();
3329 test_SHCreateWorkerWindowA();
3330 test_SHIShellFolder_EnumObjects();
3331 test_SHGetIniString();
3332 test_SHSetIniString();
3333 test_SHGetShellKey();
3334 test_SHSetParentHwnd();
3335 test_IUnknown_GetClassID();
3336 test_DllGetVersion();
3338 FreeLibrary(hshell32
);
3339 FreeLibrary(hmlang
);