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 %p %x %x %p %p %p %p\n",This
,dispIdMember
,riid
,lcid
,wFlags
,pDispParams
,pVarResult
,pExcepInfo
,puArgErr
);
1020 ok(dispIdMember
== 0xa0 || dispIdMember
== 0xa1, "Unknown dispIdMember\n");
1021 ok(pDispParams
!= NULL
, "Invoked with NULL pDispParams\n");
1022 ok(wFlags
== DISPATCH_METHOD
, "Wrong flags %x\n",wFlags
);
1023 ok(lcid
== 0,"Wrong lcid %x\n",lcid
);
1024 if (dispIdMember
== 0xa0)
1026 ok(pDispParams
->cArgs
== 0, "params.cArgs = %d\n", pDispParams
->cArgs
);
1027 ok(pDispParams
->cNamedArgs
== 0, "params.cNamedArgs = %d\n", pDispParams
->cArgs
);
1028 ok(pDispParams
->rgdispidNamedArgs
== NULL
, "params.rgdispidNamedArgs = %p\n", pDispParams
->rgdispidNamedArgs
);
1029 ok(pDispParams
->rgvarg
== NULL
, "params.rgvarg = %p\n", pDispParams
->rgvarg
);
1031 else if (dispIdMember
== 0xa1)
1033 ok(pDispParams
->cArgs
== 2, "params.cArgs = %d\n", pDispParams
->cArgs
);
1034 ok(pDispParams
->cNamedArgs
== 0, "params.cNamedArgs = %d\n", pDispParams
->cArgs
);
1035 ok(pDispParams
->rgdispidNamedArgs
== NULL
, "params.rgdispidNamedArgs = %p\n", pDispParams
->rgdispidNamedArgs
);
1036 ok(V_VT(pDispParams
->rgvarg
) == VT_BSTR
, "V_VT(var) = %d\n", V_VT(pDispParams
->rgvarg
));
1037 ok(V_I4(pDispParams
->rgvarg
) == 0xdeadcafe , "failed %p\n", V_BSTR(pDispParams
->rgvarg
));
1038 ok(V_VT(pDispParams
->rgvarg
+1) == VT_I4
, "V_VT(var) = %d\n", V_VT(pDispParams
->rgvarg
+1));
1039 ok(V_I4(pDispParams
->rgvarg
+1) == 0xdeadbeef, "failed %x\n", V_I4(pDispParams
->rgvarg
+1));
1042 return ERROR_SUCCESS
;
1045 static const IDispatchVtbl disp_vtbl
= {
1046 Disp_QueryInterface
,
1050 Disp_GetTypeInfoCount
,
1056 static HRESULT WINAPI
Enum_QueryInterface(
1057 IEnumConnections
* This
,
1063 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IEnumConnections
))
1070 IEnumConnections_AddRef(This
);
1074 trace("no interface\n");
1075 return E_NOINTERFACE
;
1078 static ULONG WINAPI
Enum_AddRef(IEnumConnections
* This
)
1080 EnumCon
*iface
= impl_from_IEnumConnections(This
);
1081 return InterlockedIncrement(&iface
->refCount
);
1084 static ULONG WINAPI
Enum_Release(IEnumConnections
* This
)
1086 EnumCon
*iface
= impl_from_IEnumConnections(This
);
1089 ret
= InterlockedDecrement(&iface
->refCount
);
1091 HeapFree(GetProcessHeap(),0,This
);
1095 static HRESULT WINAPI
Enum_Next(
1096 IEnumConnections
* This
,
1101 EnumCon
*iface
= impl_from_IEnumConnections(This
);
1103 if (cConnections
> 0 && iface
->idx
< iface
->pt
->sinkCount
)
1105 rgcd
->pUnk
= iface
->pt
->sink
[iface
->idx
];
1106 IUnknown_AddRef(iface
->pt
->sink
[iface
->idx
]);
1107 rgcd
->dwCookie
=0xff;
1117 static HRESULT WINAPI
Enum_Skip(
1118 IEnumConnections
* This
,
1124 static HRESULT WINAPI
Enum_Reset(
1125 IEnumConnections
* This
)
1130 static HRESULT WINAPI
Enum_Clone(
1131 IEnumConnections
* This
,
1132 IEnumConnections
**ppEnum
)
1137 static const IEnumConnectionsVtbl enum_vtbl
= {
1139 Enum_QueryInterface
,
1148 static HRESULT WINAPI
ConPt_QueryInterface(
1149 IConnectionPoint
* This
,
1155 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IConnectionPoint
))
1162 IConnectionPoint_AddRef(This
);
1166 trace("no interface\n");
1167 return E_NOINTERFACE
;
1170 static ULONG WINAPI
ConPt_AddRef(
1171 IConnectionPoint
* This
)
1173 ConPt
*iface
= impl_from_IConnectionPoint(This
);
1174 return InterlockedIncrement(&iface
->refCount
);
1177 static ULONG WINAPI
ConPt_Release(
1178 IConnectionPoint
* This
)
1180 ConPt
*iface
= impl_from_IConnectionPoint(This
);
1183 ret
= InterlockedDecrement(&iface
->refCount
);
1186 if (iface
->sinkCount
> 0)
1189 for (i
= 0; i
< iface
->sinkCount
; i
++)
1192 IUnknown_Release(iface
->sink
[i
]);
1194 HeapFree(GetProcessHeap(),0,iface
->sink
);
1196 HeapFree(GetProcessHeap(),0,This
);
1201 static HRESULT WINAPI
ConPt_GetConnectionInterface(
1202 IConnectionPoint
* This
,
1206 ConPt
*iface
= impl_from_IConnectionPoint(This
);
1213 memcpy(pIID
,&iface
->id
,sizeof(GUID
));
1217 static HRESULT WINAPI
ConPt_GetConnectionPointContainer(
1218 IConnectionPoint
* This
,
1219 IConnectionPointContainer
**ppCPC
)
1221 ConPt
*iface
= impl_from_IConnectionPoint(This
);
1223 *ppCPC
= &iface
->container
->IConnectionPointContainer_iface
;
1227 static HRESULT WINAPI
ConPt_Advise(
1228 IConnectionPoint
* This
,
1232 ConPt
*iface
= impl_from_IConnectionPoint(This
);
1234 if (iface
->sinkCount
== 0)
1235 iface
->sink
= HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown
*));
1237 iface
->sink
= HeapReAlloc(GetProcessHeap(),0,iface
->sink
,sizeof(IUnknown
*)*(iface
->sinkCount
+1));
1238 iface
->sink
[iface
->sinkCount
] = pUnkSink
;
1239 IUnknown_AddRef(pUnkSink
);
1241 *pdwCookie
= iface
->sinkCount
;
1245 static HRESULT WINAPI
ConPt_Unadvise(
1246 IConnectionPoint
* This
,
1249 ConPt
*iface
= impl_from_IConnectionPoint(This
);
1251 if (dwCookie
> iface
->sinkCount
)
1255 IUnknown_Release(iface
->sink
[dwCookie
-1]);
1256 iface
->sink
[dwCookie
-1] = NULL
;
1261 static HRESULT WINAPI
ConPt_EnumConnections(
1262 IConnectionPoint
* This
,
1263 IEnumConnections
**ppEnum
)
1267 ec
= HeapAlloc(GetProcessHeap(),0,sizeof(EnumCon
));
1268 ec
->IEnumConnections_iface
.lpVtbl
= &enum_vtbl
;
1270 ec
->pt
= impl_from_IConnectionPoint(This
);
1272 *ppEnum
= &ec
->IEnumConnections_iface
;
1277 static const IConnectionPointVtbl point_vtbl
= {
1278 ConPt_QueryInterface
,
1282 ConPt_GetConnectionInterface
,
1283 ConPt_GetConnectionPointContainer
,
1286 ConPt_EnumConnections
1289 static HRESULT WINAPI
EnumPt_QueryInterface(
1290 IEnumConnectionPoints
* This
,
1296 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IEnumConnectionPoints
))
1303 IEnumConnectionPoints_AddRef(This
);
1307 trace("no interface\n");
1308 return E_NOINTERFACE
;
1311 static ULONG WINAPI
EnumPt_AddRef(IEnumConnectionPoints
* This
)
1313 EnumPt
*iface
= impl_from_IEnumConnectionPoints(This
);
1314 return InterlockedIncrement(&iface
->refCount
);
1317 static ULONG WINAPI
EnumPt_Release(IEnumConnectionPoints
* This
)
1319 EnumPt
*iface
= impl_from_IEnumConnectionPoints(This
);
1322 ret
= InterlockedDecrement(&iface
->refCount
);
1324 HeapFree(GetProcessHeap(),0,This
);
1328 static HRESULT WINAPI
EnumPt_Next(
1329 IEnumConnectionPoints
* This
,
1331 IConnectionPoint
**rgcd
,
1334 EnumPt
*iface
= impl_from_IEnumConnectionPoints(This
);
1336 if (cConnections
> 0 && iface
->idx
< iface
->container
->ptCount
)
1338 *rgcd
= iface
->container
->pt
[iface
->idx
];
1339 IConnectionPoint_AddRef(iface
->container
->pt
[iface
->idx
]);
1349 static HRESULT WINAPI
EnumPt_Skip(
1350 IEnumConnectionPoints
* This
,
1356 static HRESULT WINAPI
EnumPt_Reset(
1357 IEnumConnectionPoints
* This
)
1362 static HRESULT WINAPI
EnumPt_Clone(
1363 IEnumConnectionPoints
* This
,
1364 IEnumConnectionPoints
**ppEnumPt
)
1369 static const IEnumConnectionPointsVtbl enumpt_vtbl
= {
1371 EnumPt_QueryInterface
,
1380 static HRESULT WINAPI
Contain_QueryInterface(
1381 IConnectionPointContainer
* This
,
1387 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IConnectionPointContainer
))
1394 IConnectionPointContainer_AddRef(This
);
1398 trace("no interface\n");
1399 return E_NOINTERFACE
;
1402 static ULONG WINAPI
Contain_AddRef(
1403 IConnectionPointContainer
* This
)
1405 Contain
*iface
= impl_from_IConnectionPointContainer(This
);
1406 return InterlockedIncrement(&iface
->refCount
);
1409 static ULONG WINAPI
Contain_Release(
1410 IConnectionPointContainer
* This
)
1412 Contain
*iface
= impl_from_IConnectionPointContainer(This
);
1415 ret
= InterlockedDecrement(&iface
->refCount
);
1418 if (iface
->ptCount
> 0)
1421 for (i
= 0; i
< iface
->ptCount
; i
++)
1422 IConnectionPoint_Release(iface
->pt
[i
]);
1423 HeapFree(GetProcessHeap(),0,iface
->pt
);
1425 HeapFree(GetProcessHeap(),0,This
);
1430 static HRESULT WINAPI
Contain_EnumConnectionPoints(
1431 IConnectionPointContainer
* This
,
1432 IEnumConnectionPoints
**ppEnum
)
1436 ec
= HeapAlloc(GetProcessHeap(),0,sizeof(EnumPt
));
1437 ec
->IEnumConnectionPoints_iface
.lpVtbl
= &enumpt_vtbl
;
1440 ec
->container
= impl_from_IConnectionPointContainer(This
);
1441 *ppEnum
= &ec
->IEnumConnectionPoints_iface
;
1446 static HRESULT WINAPI
Contain_FindConnectionPoint(
1447 IConnectionPointContainer
* This
,
1449 IConnectionPoint
**ppCP
)
1451 Contain
*iface
= impl_from_IConnectionPointContainer(This
);
1454 if (!IsEqualIID(riid
, &IID_NULL
) || iface
->ptCount
==0)
1456 pt
= HeapAlloc(GetProcessHeap(),0,sizeof(ConPt
));
1457 pt
->IConnectionPoint_iface
.lpVtbl
= &point_vtbl
;
1461 pt
->container
= iface
;
1462 pt
->id
= IID_IDispatch
;
1464 if (iface
->ptCount
== 0)
1465 iface
->pt
=HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown
*));
1467 iface
->pt
= HeapReAlloc(GetProcessHeap(),0,iface
->pt
,sizeof(IUnknown
*)*(iface
->ptCount
+1));
1468 iface
->pt
[iface
->ptCount
] = &pt
->IConnectionPoint_iface
;
1471 *ppCP
= &pt
->IConnectionPoint_iface
;
1475 *ppCP
= iface
->pt
[0];
1476 IUnknown_AddRef((IUnknown
*)*ppCP
);
1482 static const IConnectionPointContainerVtbl contain_vtbl
= {
1483 Contain_QueryInterface
,
1487 Contain_EnumConnectionPoints
,
1488 Contain_FindConnectionPoint
1491 static void test_IConnectionPoint(void)
1495 IConnectionPoint
*point
;
1498 DWORD cookie
= 0xffffffff;
1502 if (!pIConnectionPoint_SimpleInvoke
|| !pConnectToConnectionPoint
)
1504 win_skip("IConnectionPoint Apis not present\n");
1508 container
= HeapAlloc(GetProcessHeap(),0,sizeof(Contain
));
1509 container
->IConnectionPointContainer_iface
.lpVtbl
= &contain_vtbl
;
1510 container
->refCount
= 1;
1511 container
->ptCount
= 0;
1512 container
->pt
= NULL
;
1514 dispatch
= HeapAlloc(GetProcessHeap(),0,sizeof(Disp
));
1515 dispatch
->IDispatch_iface
.lpVtbl
= &disp_vtbl
;
1516 dispatch
->refCount
= 1;
1518 rc
= pConnectToConnectionPoint((IUnknown
*)dispatch
, &IID_NULL
, TRUE
, (IUnknown
*)container
, &cookie
, &point
);
1519 ok(rc
== S_OK
, "pConnectToConnectionPoint failed with %x\n",rc
);
1520 ok(point
!= NULL
, "returned ConnectionPoint is NULL\n");
1521 ok(cookie
!= 0xffffffff, "invalid cookie returned\n");
1523 rc
= pIConnectionPoint_SimpleInvoke(point
,0xa0,NULL
);
1524 ok(rc
== S_OK
, "pConnectToConnectionPoint failed with %x\n",rc
);
1526 if (pSHPackDispParams
)
1528 memset(¶ms
, 0xc0, sizeof(params
));
1529 memset(vars
, 0xc0, sizeof(vars
));
1530 rc
= pSHPackDispParams(¶ms
, vars
, 2, VT_I4
, 0xdeadbeef, VT_BSTR
, 0xdeadcafe);
1531 ok(rc
== S_OK
, "SHPackDispParams failed: %08x\n", rc
);
1533 rc
= pIConnectionPoint_SimpleInvoke(point
,0xa1,¶ms
);
1534 ok(rc
== S_OK
, "pConnectToConnectionPoint failed with %x\n",rc
);
1537 win_skip("pSHPackDispParams not present\n");
1539 rc
= pConnectToConnectionPoint(NULL
, &IID_NULL
, FALSE
, (IUnknown
*)container
, &cookie
, NULL
);
1540 ok(rc
== S_OK
, "pConnectToConnectionPoint failed with %x\n",rc
);
1542 /* MSDN says this should be required but it crashs on XP
1543 IUnknown_Release(point);
1545 ref
= IUnknown_Release((IUnknown
*)container
);
1546 ok(ref
== 0, "leftover IConnectionPointContainer reference %i\n",ref
);
1547 ref
= IUnknown_Release((IUnknown
*)dispatch
);
1548 ok(ref
== 0, "leftover IDispatch reference %i\n",ref
);
1551 typedef struct _propbag
1553 IPropertyBag IPropertyBag_iface
;
1558 static inline PropBag
*impl_from_IPropertyBag(IPropertyBag
*iface
)
1560 return CONTAINING_RECORD(iface
, PropBag
, IPropertyBag_iface
);
1564 static HRESULT WINAPI
Prop_QueryInterface(
1571 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IPropertyBag
))
1578 IPropertyBag_AddRef(This
);
1582 trace("no interface\n");
1583 return E_NOINTERFACE
;
1586 static ULONG WINAPI
Prop_AddRef(
1589 PropBag
*iface
= impl_from_IPropertyBag(This
);
1590 return InterlockedIncrement(&iface
->refCount
);
1593 static ULONG WINAPI
Prop_Release(
1596 PropBag
*iface
= impl_from_IPropertyBag(This
);
1599 ret
= InterlockedDecrement(&iface
->refCount
);
1601 HeapFree(GetProcessHeap(),0,This
);
1605 static HRESULT WINAPI
Prop_Read(
1607 LPCOLESTR pszPropName
,
1609 IErrorLog
*pErrorLog
)
1611 V_VT(pVar
) = VT_BLOB
|VT_BYREF
;
1612 V_BYREF(pVar
) = (LPVOID
)0xdeadcafe;
1616 static HRESULT WINAPI
Prop_Write(
1618 LPCOLESTR pszPropName
,
1625 static const IPropertyBagVtbl prop_vtbl
= {
1626 Prop_QueryInterface
,
1634 static void test_SHPropertyBag_ReadLONG(void)
1639 static const WCHAR szName1
[] = {'n','a','m','e','1',0};
1641 if (!pSHPropertyBag_ReadLONG
)
1643 win_skip("SHPropertyBag_ReadLONG not present\n");
1647 pb
= HeapAlloc(GetProcessHeap(),0,sizeof(PropBag
));
1649 pb
->IPropertyBag_iface
.lpVtbl
= &prop_vtbl
;
1652 rc
= pSHPropertyBag_ReadLONG(NULL
, szName1
, &out
);
1653 ok(rc
== E_INVALIDARG
|| broken(rc
== S_OK
), "incorrect return %x\n",rc
);
1654 ok(out
== 0xfeedface, "value should not have changed\n");
1655 rc
= pSHPropertyBag_ReadLONG(&pb
->IPropertyBag_iface
, NULL
, &out
);
1656 ok(rc
== E_INVALIDARG
|| broken(rc
== S_OK
) || broken(rc
== S_FALSE
), "incorrect return %x\n",rc
);
1657 ok(out
== 0xfeedface, "value should not have changed\n");
1658 rc
= pSHPropertyBag_ReadLONG(&pb
->IPropertyBag_iface
, szName1
, NULL
);
1659 ok(rc
== E_INVALIDARG
|| broken(rc
== S_OK
) || broken(rc
== S_FALSE
), "incorrect return %x\n",rc
);
1660 rc
= pSHPropertyBag_ReadLONG(&pb
->IPropertyBag_iface
, szName1
, &out
);
1661 ok(rc
== DISP_E_BADVARTYPE
|| broken(rc
== S_OK
) || broken(rc
== S_FALSE
), "incorrect return %x\n",rc
);
1662 ok(out
== 0xfeedface || broken(out
== 0xfeedfa00), "value should not have changed %x\n",out
);
1663 IUnknown_Release((IUnknown
*)pb
);
1666 static void test_SHSetWindowBits(void)
1669 DWORD style
, styleold
;
1672 if(!pSHSetWindowBits
)
1674 win_skip("SHSetWindowBits is not available\n");
1679 clsA
.lpfnWndProc
= DefWindowProcA
;
1680 clsA
.cbClsExtra
= 0;
1681 clsA
.cbWndExtra
= 0;
1682 clsA
.hInstance
= GetModuleHandleA(NULL
);
1684 clsA
.hCursor
= LoadCursorA(0, (LPSTR
)IDC_ARROW
);
1685 clsA
.hbrBackground
= NULL
;
1686 clsA
.lpszMenuName
= NULL
;
1687 clsA
.lpszClassName
= "Shlwapi test class";
1688 RegisterClassA(&clsA
);
1690 hwnd
= CreateWindowA("Shlwapi test class", "Test", WS_VISIBLE
, 0, 0, 100, 100,
1691 NULL
, NULL
, GetModuleHandleA(NULL
), 0);
1692 ok(IsWindow(hwnd
), "failed to create window\n");
1695 SetLastError(0xdeadbeef);
1696 style
= pSHSetWindowBits(NULL
, GWL_STYLE
, 0, 0);
1697 ok(style
== 0, "expected 0 retval, got %d\n", style
);
1698 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE
||
1699 broken(GetLastError() == 0xdeadbeef), /* Win9x/WinMe */
1700 "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
1702 /* zero mask, zero flags */
1703 styleold
= GetWindowLongA(hwnd
, GWL_STYLE
);
1704 style
= pSHSetWindowBits(hwnd
, GWL_STYLE
, 0, 0);
1705 ok(styleold
== style
, "expected old style\n");
1706 ok(styleold
== GetWindowLongA(hwnd
, GWL_STYLE
), "expected to keep old style\n");
1709 styleold
= GetWindowLongA(hwnd
, GWL_STYLE
);
1710 ok(styleold
& WS_VISIBLE
, "expected WS_VISIBLE\n");
1711 style
= pSHSetWindowBits(hwnd
, GWL_STYLE
, WS_VISIBLE
, 0);
1713 ok(style
== styleold
, "expected previous style, got %x\n", style
);
1714 ok((GetWindowLongA(hwnd
, GWL_STYLE
) & WS_VISIBLE
) == 0, "expected updated style\n");
1716 /* test mask, unset style bit used */
1717 styleold
= GetWindowLongA(hwnd
, GWL_STYLE
);
1718 style
= pSHSetWindowBits(hwnd
, GWL_STYLE
, WS_VISIBLE
, 0);
1719 ok(style
== styleold
, "expected previous style, got %x\n", style
);
1720 ok(styleold
== GetWindowLongA(hwnd
, GWL_STYLE
), "expected to keep old style\n");
1722 /* set back with flags */
1723 styleold
= GetWindowLongA(hwnd
, GWL_STYLE
);
1724 style
= pSHSetWindowBits(hwnd
, GWL_STYLE
, WS_VISIBLE
, WS_VISIBLE
);
1725 ok(style
== styleold
, "expected previous style, got %x\n", style
);
1726 ok(GetWindowLongA(hwnd
, GWL_STYLE
) & WS_VISIBLE
, "expected updated style\n");
1728 /* reset and try to set without a mask */
1729 pSHSetWindowBits(hwnd
, GWL_STYLE
, WS_VISIBLE
, 0);
1730 ok((GetWindowLongA(hwnd
, GWL_STYLE
) & WS_VISIBLE
) == 0, "expected updated style\n");
1731 styleold
= GetWindowLongA(hwnd
, GWL_STYLE
);
1732 style
= pSHSetWindowBits(hwnd
, GWL_STYLE
, 0, WS_VISIBLE
);
1733 ok(style
== styleold
, "expected previous style, got %x\n", style
);
1734 ok((GetWindowLongA(hwnd
, GWL_STYLE
) & WS_VISIBLE
) == 0, "expected updated style\n");
1736 DestroyWindow(hwnd
);
1738 UnregisterClassA("Shlwapi test class", GetModuleHandleA(NULL
));
1741 static void test_SHFormatDateTimeA(void)
1743 FILETIME UNALIGNED filetime
;
1744 CHAR buff
[100], buff2
[100], buff3
[100];
1749 if(!pSHFormatDateTimeA
)
1751 win_skip("pSHFormatDateTimeA isn't available\n");
1757 /* crashes on native */
1758 pSHFormatDateTimeA(NULL
, NULL
, NULL
, 0);
1762 SystemTimeToFileTime(&st
, &filetime
);
1763 /* SHFormatDateTime expects input as utc */
1764 LocalFileTimeToFileTime(&filetime
, &filetime
);
1766 /* no way to get required buffer length here */
1767 SetLastError(0xdeadbeef);
1768 ret
= pSHFormatDateTimeA(&filetime
, NULL
, NULL
, 0);
1769 ok(ret
== 0, "got %d\n", ret
);
1770 ok(GetLastError() == 0xdeadbeef || broken(GetLastError() == ERROR_SUCCESS
/* Win7 */),
1771 "expected 0xdeadbeef, got %d\n", GetLastError());
1773 SetLastError(0xdeadbeef);
1774 buff
[0] = 'a'; buff
[1] = 0;
1775 ret
= pSHFormatDateTimeA(&filetime
, NULL
, buff
, 0);
1776 ok(ret
== 0, "got %d\n", ret
);
1777 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1778 ok(buff
[0] == 'a', "expected same string, got %s\n", buff
);
1780 /* flags needs to have FDTF_NOAUTOREADINGORDER for these tests to succeed on Vista+ */
1782 /* all combinations documented as invalid succeeded */
1783 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_SHORTTIME
| FDTF_LONGTIME
;
1784 SetLastError(0xdeadbeef);
1785 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1786 ok(ret
== lstrlenA(buff
)+1, "got %d\n", ret
);
1787 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1789 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_SHORTDATE
| FDTF_LONGDATE
;
1790 SetLastError(0xdeadbeef);
1791 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1792 ok(ret
== lstrlenA(buff
)+1, "got %d\n", ret
);
1793 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1795 flags
= FDTF_SHORTDATE
| FDTF_LTRDATE
| FDTF_RTLDATE
;
1796 SetLastError(0xdeadbeef);
1797 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1798 ok(ret
== lstrlenA(buff
)+1, "got %d\n", ret
);
1799 ok(GetLastError() == 0xdeadbeef ||
1800 broken(GetLastError() == ERROR_INVALID_FLAGS
), /* Win9x/WinMe */
1801 "expected 0xdeadbeef, got %d\n", GetLastError());
1803 /* now check returned strings */
1804 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_SHORTTIME
;
1805 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1806 ok(ret
== lstrlenA(buff
)+1, "got %d\n", ret
);
1807 ret
= GetTimeFormatA(LOCALE_USER_DEFAULT
, TIME_NOSECONDS
, &st
, NULL
, buff2
, sizeof(buff2
));
1808 ok(ret
== lstrlenA(buff2
)+1, "got %d\n", ret
);
1809 ok(lstrcmpA(buff
, buff2
) == 0, "expected (%s), got (%s)\n", buff2
, buff
);
1811 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_LONGTIME
;
1812 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1813 ok(ret
== lstrlenA(buff
)+1, "got %d\n", ret
);
1814 ret
= GetTimeFormatA(LOCALE_USER_DEFAULT
, 0, &st
, NULL
, buff2
, sizeof(buff2
));
1815 ok(ret
== lstrlenA(buff2
)+1, "got %d\n", ret
);
1816 ok(lstrcmpA(buff
, buff2
) == 0, "expected (%s), got (%s)\n", buff2
, buff
);
1818 /* both time flags */
1819 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_LONGTIME
| FDTF_SHORTTIME
;
1820 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1821 ok(ret
== lstrlenA(buff
)+1, "got %d\n", ret
);
1822 ret
= GetTimeFormatA(LOCALE_USER_DEFAULT
, 0, &st
, NULL
, buff2
, sizeof(buff2
));
1823 ok(ret
== lstrlenA(buff2
)+1, "got %d\n", ret
);
1824 ok(lstrcmpA(buff
, buff2
) == 0, "expected (%s), got (%s)\n", buff2
, buff
);
1826 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_SHORTDATE
;
1827 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1828 ok(ret
== lstrlenA(buff
)+1, "got %d\n", ret
);
1829 ret
= GetDateFormatA(LOCALE_USER_DEFAULT
, DATE_SHORTDATE
, &st
, NULL
, buff2
, sizeof(buff2
));
1830 ok(ret
== lstrlenA(buff2
)+1, "got %d\n", ret
);
1831 ok(lstrcmpA(buff
, buff2
) == 0, "expected (%s), got (%s)\n", buff2
, buff
);
1833 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_LONGDATE
;
1834 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1835 ok(ret
== lstrlenA(buff
)+1, "got %d\n", ret
);
1836 ret
= GetDateFormatA(LOCALE_USER_DEFAULT
, DATE_LONGDATE
, &st
, NULL
, buff2
, sizeof(buff2
));
1837 ok(ret
== lstrlenA(buff2
)+1, "got %d\n", ret
);
1838 ok(lstrcmpA(buff
, buff2
) == 0, "expected (%s), got (%s)\n", buff2
, buff
);
1840 /* both date flags */
1841 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_LONGDATE
| FDTF_SHORTDATE
;
1842 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1843 ok(ret
== lstrlenA(buff
)+1, "got %d\n", ret
);
1844 ret
= GetDateFormatA(LOCALE_USER_DEFAULT
, DATE_LONGDATE
, &st
, NULL
, buff2
, sizeof(buff2
));
1845 ok(ret
== lstrlenA(buff2
)+1, "got %d\n", ret
);
1846 ok(lstrcmpA(buff
, buff2
) == 0, "expected (%s), got (%s)\n", buff2
, buff
);
1848 /* various combinations of date/time flags */
1849 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_LONGDATE
| FDTF_SHORTTIME
;
1850 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1851 ok(ret
== lstrlenA(buff
)+1, "got %d, length %d\n", ret
, lstrlenA(buff
)+1);
1852 ret
= GetTimeFormatA(LOCALE_USER_DEFAULT
, TIME_NOSECONDS
, &st
, NULL
, buff3
, sizeof(buff3
));
1853 ok(ret
== lstrlenA(buff3
)+1, "got %d\n", ret
);
1854 ok(lstrcmpA(buff3
, buff
+ lstrlenA(buff
) - lstrlenA(buff3
)) == 0,
1855 "expected (%s), got (%s) for time part\n",
1856 buff3
, buff
+ lstrlenA(buff
) - lstrlenA(buff3
));
1857 ret
= GetDateFormatA(LOCALE_USER_DEFAULT
, DATE_LONGDATE
, &st
, NULL
, buff2
, sizeof(buff2
));
1858 ok(ret
== lstrlenA(buff2
)+1, "got %d\n", ret
);
1859 buff
[lstrlenA(buff2
)] = '\0';
1860 ok(lstrcmpA(buff2
, buff
) == 0, "expected (%s) got (%s) for date part\n",
1863 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_LONGDATE
| FDTF_LONGTIME
;
1864 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1865 ok(ret
== lstrlenA(buff
)+1, "got %d\n", ret
);
1866 ret
= GetTimeFormatA(LOCALE_USER_DEFAULT
, 0, &st
, NULL
, buff3
, sizeof(buff3
));
1867 ok(ret
== lstrlenA(buff3
)+1, "got %d\n", ret
);
1868 ok(lstrcmpA(buff3
, buff
+ lstrlenA(buff
) - lstrlenA(buff3
)) == 0,
1869 "expected (%s), got (%s) for time part\n",
1870 buff3
, buff
+ lstrlenA(buff
) - lstrlenA(buff3
));
1871 ret
= GetDateFormatA(LOCALE_USER_DEFAULT
, DATE_LONGDATE
, &st
, NULL
, buff2
, sizeof(buff2
));
1872 ok(ret
== lstrlenA(buff2
)+1, "got %d\n", ret
);
1873 buff
[lstrlenA(buff2
)] = '\0';
1874 ok(lstrcmpA(buff2
, buff
) == 0, "expected (%s) got (%s) for date part\n",
1877 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_SHORTDATE
| FDTF_SHORTTIME
;
1878 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1879 ok(ret
== lstrlenA(buff
)+1, "got %d\n", ret
);
1880 ret
= GetDateFormatA(LOCALE_USER_DEFAULT
, DATE_SHORTDATE
, &st
, NULL
, buff2
, sizeof(buff2
));
1881 ok(ret
== lstrlenA(buff2
)+1, "got %d\n", ret
);
1883 ret
= GetTimeFormatA(LOCALE_USER_DEFAULT
, TIME_NOSECONDS
, &st
, NULL
, buff3
, sizeof(buff3
));
1884 ok(ret
== lstrlenA(buff3
)+1, "got %d\n", ret
);
1885 strcat(buff2
, buff3
);
1886 ok(lstrcmpA(buff
, buff2
) == 0, "expected (%s), got (%s)\n", buff2
, buff
);
1888 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_SHORTDATE
| FDTF_LONGTIME
;
1889 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1890 ok(ret
== lstrlenA(buff
)+1, "got %d\n", ret
);
1891 ret
= GetDateFormatA(LOCALE_USER_DEFAULT
, DATE_SHORTDATE
, &st
, NULL
, buff2
, sizeof(buff2
));
1892 ok(ret
== lstrlenA(buff2
)+1, "got %d\n", ret
);
1894 ret
= GetTimeFormatA(LOCALE_USER_DEFAULT
, 0, &st
, NULL
, buff3
, sizeof(buff3
));
1895 ok(ret
== lstrlenA(buff3
)+1, "got %d\n", ret
);
1896 strcat(buff2
, buff3
);
1897 ok(lstrcmpA(buff
, buff2
) == 0, "expected (%s), got (%s)\n", buff2
, buff
);
1900 static void test_SHFormatDateTimeW(void)
1902 FILETIME UNALIGNED filetime
;
1903 WCHAR buff
[100], buff2
[100], buff3
[100], *p1
, *p2
;
1907 static const WCHAR spaceW
[] = {' ',0};
1908 #define UNICODE_LTR_MARK 0x200e
1909 #define UNICODE_RTL_MARK 0x200f
1911 if(!pSHFormatDateTimeW
)
1913 win_skip("pSHFormatDateTimeW isn't available\n");
1919 /* crashes on native */
1920 pSHFormatDateTimeW(NULL
, NULL
, NULL
, 0);
1924 SystemTimeToFileTime(&st
, &filetime
);
1925 /* SHFormatDateTime expects input as utc */
1926 LocalFileTimeToFileTime(&filetime
, &filetime
);
1928 /* no way to get required buffer length here */
1929 SetLastError(0xdeadbeef);
1930 ret
= pSHFormatDateTimeW(&filetime
, NULL
, NULL
, 0);
1931 ok(ret
== 0, "expected 0, got %d\n", ret
);
1932 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1934 SetLastError(0xdeadbeef);
1935 buff
[0] = 'a'; buff
[1] = 0;
1936 ret
= pSHFormatDateTimeW(&filetime
, NULL
, buff
, 0);
1937 ok(ret
== 0, "expected 0, got %d\n", ret
);
1938 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1939 ok(buff
[0] == 'a', "expected same string\n");
1941 /* all combinations documented as invalid succeeded */
1942 flags
= FDTF_SHORTTIME
| FDTF_LONGTIME
;
1943 SetLastError(0xdeadbeef);
1944 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
1945 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
1946 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
1947 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1949 flags
= FDTF_SHORTDATE
| FDTF_LONGDATE
;
1950 SetLastError(0xdeadbeef);
1951 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
1952 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
1953 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
1954 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1956 flags
= FDTF_SHORTDATE
| FDTF_LTRDATE
| FDTF_RTLDATE
;
1957 SetLastError(0xdeadbeef);
1958 buff
[0] = 0; /* NT4 doesn't clear the buffer on failure */
1959 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
1960 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
1961 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
1962 ok(GetLastError() == 0xdeadbeef ||
1963 broken(GetLastError() == ERROR_INVALID_FLAGS
), /* Win9x/WinMe/NT4 */
1964 "expected 0xdeadbeef, got %d\n", GetLastError());
1966 /* now check returned strings */
1967 flags
= FDTF_SHORTTIME
;
1968 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
1969 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
1970 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
1971 SetLastError(0xdeadbeef);
1972 ret
= GetTimeFormatW(LOCALE_USER_DEFAULT
, TIME_NOSECONDS
, &st
, NULL
, buff2
, sizeof(buff2
)/sizeof(WCHAR
));
1973 if (ret
== 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1975 win_skip("Needed W-functions are not implemented\n");
1978 ok(ret
== lstrlenW(buff2
)+1, "expected %d, got %d\n", lstrlenW(buff2
)+1, ret
);
1979 ok(lstrcmpW(buff
, buff2
) == 0, "expected equal strings\n");
1981 flags
= FDTF_LONGTIME
;
1982 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
1983 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
1984 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
1985 ret
= GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, &st
, NULL
, buff2
, sizeof(buff2
)/sizeof(WCHAR
));
1986 ok(ret
== lstrlenW(buff2
)+1, "expected %d, got %d\n", lstrlenW(buff2
)+1, ret
);
1987 ok(lstrcmpW(buff
, buff2
) == 0, "expected equal strings\n");
1989 /* both time flags */
1990 flags
= FDTF_LONGTIME
| FDTF_SHORTTIME
;
1991 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
1992 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
1993 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
1994 ret
= GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, &st
, NULL
, buff2
, sizeof(buff2
)/sizeof(WCHAR
));
1995 ok(ret
== lstrlenW(buff2
)+1, "expected %d, got %d\n", lstrlenW(buff2
)+1, ret
);
1996 ok(lstrcmpW(buff
, buff2
) == 0, "expected equal string\n");
1998 flags
= FDTF_SHORTDATE
;
1999 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
2000 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
2001 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
2002 ret
= GetDateFormatW(LOCALE_USER_DEFAULT
, DATE_SHORTDATE
, &st
, NULL
, buff2
, sizeof(buff2
)/sizeof(WCHAR
));
2003 ok(ret
== lstrlenW(buff2
)+1, "expected %d, got %d\n", lstrlenW(buff2
)+1, ret
);
2004 ok(lstrcmpW(buff
, buff2
) == 0, "expected equal strings\n");
2006 flags
= FDTF_LONGDATE
;
2007 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
2008 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
2009 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
2010 ret
= GetDateFormatW(LOCALE_USER_DEFAULT
, DATE_LONGDATE
, &st
, NULL
, buff2
, sizeof(buff2
)/sizeof(WCHAR
));
2011 ok(ret
== lstrlenW(buff2
)+1, "expected %d, got %d\n", lstrlenW(buff2
)+1, ret
);
2012 ok(lstrcmpW(buff
, buff2
) == 0, "expected equal strings\n");
2014 /* both date flags */
2015 flags
= FDTF_LONGDATE
| FDTF_SHORTDATE
;
2016 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
2017 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
2018 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
2019 ret
= GetDateFormatW(LOCALE_USER_DEFAULT
, DATE_LONGDATE
, &st
, NULL
, buff2
, sizeof(buff2
)/sizeof(WCHAR
));
2020 ok(ret
== lstrlenW(buff2
)+1, "expected %d, got %d\n", lstrlenW(buff2
)+1, ret
);
2021 ok(lstrcmpW(buff
, buff2
) == 0, "expected equal strings\n");
2023 /* various combinations of date/time flags */
2024 flags
= FDTF_LONGDATE
| FDTF_SHORTTIME
;
2025 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
2026 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
2027 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
2028 ret
= GetTimeFormatW(LOCALE_USER_DEFAULT
, TIME_NOSECONDS
, &st
, NULL
, buff3
, sizeof(buff3
)/sizeof(WCHAR
));
2029 ok(ret
== lstrlenW(buff3
)+1, "expected %d, got %d\n", lstrlenW(buff3
)+1, ret
);
2030 ok(lstrcmpW(buff3
, buff
+ lstrlenW(buff
) - lstrlenW(buff3
)) == 0,
2031 "expected (%s), got (%s) for time part\n",
2032 wine_dbgstr_w(buff3
), wine_dbgstr_w(buff
+ lstrlenW(buff
) - lstrlenW(buff3
)));
2033 ret
= GetDateFormatW(LOCALE_USER_DEFAULT
, DATE_LONGDATE
, &st
, NULL
, buff2
, sizeof(buff2
)/sizeof(WCHAR
));
2034 ok(ret
== lstrlenW(buff2
)+1, "expected %d, got %d\n", lstrlenW(buff2
)+1, ret
);
2039 while (*p1
== UNICODE_LTR_MARK
|| *p1
== UNICODE_RTL_MARK
)
2041 while (*p2
== UNICODE_LTR_MARK
|| *p2
== UNICODE_RTL_MARK
)
2047 ok(lstrcmpW(buff2
, buff
) == 0, "expected (%s) got (%s) for date part\n",
2048 wine_dbgstr_w(buff2
), wine_dbgstr_w(buff
));
2050 flags
= FDTF_LONGDATE
| FDTF_LONGTIME
;
2051 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
2052 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
2053 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
2054 ret
= GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, &st
, NULL
, buff3
, sizeof(buff3
)/sizeof(WCHAR
));
2055 ok(ret
== lstrlenW(buff3
)+1, "expected %d, got %d\n", lstrlenW(buff3
)+1, ret
);
2056 ok(lstrcmpW(buff3
, buff
+ lstrlenW(buff
) - lstrlenW(buff3
)) == 0,
2057 "expected (%s), got (%s) for time part\n",
2058 wine_dbgstr_w(buff3
), wine_dbgstr_w(buff
+ lstrlenW(buff
) - lstrlenW(buff3
)));
2059 ret
= GetDateFormatW(LOCALE_USER_DEFAULT
, DATE_LONGDATE
, &st
, NULL
, buff2
, sizeof(buff2
)/sizeof(WCHAR
));
2060 ok(ret
== lstrlenW(buff2
)+1, "expected %d, got %d\n", lstrlenW(buff2
)+1, ret
);
2065 while (*p1
== UNICODE_LTR_MARK
|| *p1
== UNICODE_RTL_MARK
)
2067 while (*p2
== UNICODE_LTR_MARK
|| *p2
== UNICODE_RTL_MARK
)
2073 ok(lstrcmpW(buff2
, buff
) == 0, "expected (%s) got (%s) for date part\n",
2074 wine_dbgstr_w(buff2
), wine_dbgstr_w(buff
));
2076 flags
= FDTF_SHORTDATE
| FDTF_SHORTTIME
;
2077 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
2078 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
2079 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
2080 ret
= GetDateFormatW(LOCALE_USER_DEFAULT
, DATE_SHORTDATE
, &st
, NULL
, buff2
, sizeof(buff2
)/sizeof(WCHAR
));
2081 ok(ret
== lstrlenW(buff2
)+1, "expected %d, got %d\n", lstrlenW(buff2
)+1, ret
);
2082 lstrcatW(buff2
, spaceW
);
2083 ret
= GetTimeFormatW(LOCALE_USER_DEFAULT
, TIME_NOSECONDS
, &st
, NULL
, buff3
, sizeof(buff3
)/sizeof(WCHAR
));
2084 ok(ret
== lstrlenW(buff3
)+1, "expected %d, got %d\n", lstrlenW(buff3
)+1, ret
);
2085 lstrcatW(buff2
, buff3
);
2086 ok(lstrcmpW(buff
, buff2
) == 0, "expected equal strings\n");
2088 flags
= FDTF_SHORTDATE
| FDTF_LONGTIME
;
2089 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
2090 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
2091 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
2092 ret
= GetDateFormatW(LOCALE_USER_DEFAULT
, DATE_SHORTDATE
, &st
, NULL
, buff2
, sizeof(buff2
)/sizeof(WCHAR
));
2093 ok(ret
== lstrlenW(buff2
)+1, "expected %d, got %d\n", lstrlenW(buff2
)+1, ret
);
2094 lstrcatW(buff2
, spaceW
);
2095 ret
= GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, &st
, NULL
, buff3
, sizeof(buff3
)/sizeof(WCHAR
));
2096 ok(ret
== lstrlenW(buff3
)+1, "expected %d, got %d\n", lstrlenW(buff3
)+1, ret
);
2097 lstrcatW(buff2
, buff3
);
2098 ok(lstrcmpW(buff
, buff2
) == 0, "expected equal strings\n");
2101 static void test_SHGetObjectCompatFlags(void)
2103 struct compat_value
{
2108 struct compat_value values
[] = {
2109 { "OTNEEDSSFCACHE", 0x1 },
2110 { "NO_WEBVIEW", 0x2 },
2111 { "UNBINDABLE", 0x4 },
2113 { "NEEDSFILESYSANCESTOR", 0x10 },
2114 { "NOTAFILESYSTEM", 0x20 },
2115 { "CTXMENU_NOVERBS", 0x40 },
2116 { "CTXMENU_LIMITEDQI", 0x80 },
2117 { "COCREATESHELLFOLDERONLY", 0x100 },
2118 { "NEEDSSTORAGEANCESTOR", 0x200 },
2119 { "NOLEGACYWEBVIEW", 0x400 },
2120 { "CTXMENU_XPQCMFLAGS", 0x1000 },
2121 { "NOIPROPERTYSTORE", 0x2000 }
2124 static const char compat_path
[] = "Software\\Microsoft\\Windows\\CurrentVersion\\ShellCompatibility\\Objects";
2125 void *pColorAdjustLuma
= GetProcAddress(hShlwapi
, "ColorAdjustLuma");
2126 CHAR keyA
[39]; /* {CLSID} */
2131 if (!pSHGetObjectCompatFlags
)
2133 win_skip("SHGetObjectCompatFlags isn't available\n");
2137 if (pColorAdjustLuma
&& pColorAdjustLuma
== pSHGetObjectCompatFlags
) /* win2k */
2139 win_skip("Skipping SHGetObjectCompatFlags, same ordinal used for ColorAdjustLuma\n");
2144 ret
= pSHGetObjectCompatFlags(NULL
, NULL
);
2145 ok(ret
== 0, "got %d\n", ret
);
2147 ret
= RegOpenKeyA(HKEY_LOCAL_MACHINE
, compat_path
, &root
);
2148 if (ret
!= ERROR_SUCCESS
)
2150 skip("No compatibility class data found\n");
2154 for (i
= 0; RegEnumKeyA(root
, i
, keyA
, sizeof(keyA
)) == ERROR_SUCCESS
; i
++)
2158 if (RegOpenKeyA(root
, keyA
, &clsid_key
) == ERROR_SUCCESS
)
2161 DWORD expected
= 0, got
, length
= sizeof(valueA
);
2165 for (v
= 0; RegEnumValueA(clsid_key
, v
, valueA
, &length
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
; v
++)
2169 for (j
= 0; j
< sizeof(values
)/sizeof(struct compat_value
); j
++)
2170 if (lstrcmpA(values
[j
].nameA
, valueA
) == 0)
2172 expected
|= values
[j
].value
;
2176 length
= sizeof(valueA
);
2179 pGUIDFromStringA(keyA
, &clsid
);
2180 got
= pSHGetObjectCompatFlags(NULL
, &clsid
);
2181 ok(got
== expected
, "got 0x%08x, expected 0x%08x. Key %s\n", got
, expected
, keyA
);
2183 RegCloseKey(clsid_key
);
2191 IOleCommandTarget IOleCommandTarget_iface
;
2193 } IOleCommandTargetImpl
;
2195 static inline IOleCommandTargetImpl
*impl_from_IOleCommandTarget(IOleCommandTarget
*iface
)
2197 return CONTAINING_RECORD(iface
, IOleCommandTargetImpl
, IOleCommandTarget_iface
);
2200 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl
;
2202 static IOleCommandTarget
* IOleCommandTargetImpl_Construct(void)
2204 IOleCommandTargetImpl
*obj
;
2206 obj
= HeapAlloc(GetProcessHeap(), 0, sizeof(*obj
));
2207 obj
->IOleCommandTarget_iface
.lpVtbl
= &IOleCommandTargetImpl_Vtbl
;
2210 return &obj
->IOleCommandTarget_iface
;
2213 static HRESULT WINAPI
IOleCommandTargetImpl_QueryInterface(IOleCommandTarget
*iface
, REFIID riid
, void **ppvObj
)
2215 IOleCommandTargetImpl
*This
= impl_from_IOleCommandTarget(iface
);
2217 if (IsEqualIID(riid
, &IID_IUnknown
) ||
2218 IsEqualIID(riid
, &IID_IOleCommandTarget
))
2225 IOleCommandTarget_AddRef(iface
);
2229 return E_NOINTERFACE
;
2232 static ULONG WINAPI
IOleCommandTargetImpl_AddRef(IOleCommandTarget
*iface
)
2234 IOleCommandTargetImpl
*This
= impl_from_IOleCommandTarget(iface
);
2235 return InterlockedIncrement(&This
->ref
);
2238 static ULONG WINAPI
IOleCommandTargetImpl_Release(IOleCommandTarget
*iface
)
2240 IOleCommandTargetImpl
*This
= impl_from_IOleCommandTarget(iface
);
2241 ULONG ref
= InterlockedDecrement(&This
->ref
);
2245 HeapFree(GetProcessHeap(), 0, This
);
2251 static HRESULT WINAPI
IOleCommandTargetImpl_QueryStatus(
2252 IOleCommandTarget
*iface
, const GUID
*group
, ULONG cCmds
, OLECMD prgCmds
[], OLECMDTEXT
*pCmdText
)
2257 static HRESULT WINAPI
IOleCommandTargetImpl_Exec(
2258 IOleCommandTarget
*iface
,
2259 const GUID
*CmdGroup
,
2265 add_call(&trace_got
, 3, CmdGroup
, (void*)(DWORD_PTR
)nCmdID
, (void*)(DWORD_PTR
)nCmdexecopt
, pvaIn
, pvaOut
);
2269 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl
=
2271 IOleCommandTargetImpl_QueryInterface
,
2272 IOleCommandTargetImpl_AddRef
,
2273 IOleCommandTargetImpl_Release
,
2274 IOleCommandTargetImpl_QueryStatus
,
2275 IOleCommandTargetImpl_Exec
2279 IServiceProvider IServiceProvider_iface
;
2281 } IServiceProviderImpl
;
2283 static inline IServiceProviderImpl
*impl_from_IServiceProvider(IServiceProvider
*iface
)
2285 return CONTAINING_RECORD(iface
, IServiceProviderImpl
, IServiceProvider_iface
);
2289 IProfferService IProfferService_iface
;
2291 } IProfferServiceImpl
;
2293 static inline IProfferServiceImpl
*impl_from_IProfferService(IProfferService
*iface
)
2295 return CONTAINING_RECORD(iface
, IProfferServiceImpl
, IProfferService_iface
);
2299 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl
;
2300 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl
;
2302 static IServiceProvider
* IServiceProviderImpl_Construct(void)
2304 IServiceProviderImpl
*obj
;
2306 obj
= HeapAlloc(GetProcessHeap(), 0, sizeof(*obj
));
2307 obj
->IServiceProvider_iface
.lpVtbl
= &IServiceProviderImpl_Vtbl
;
2310 return &obj
->IServiceProvider_iface
;
2313 static IProfferService
* IProfferServiceImpl_Construct(void)
2315 IProfferServiceImpl
*obj
;
2317 obj
= HeapAlloc(GetProcessHeap(), 0, sizeof(*obj
));
2318 obj
->IProfferService_iface
.lpVtbl
= &IProfferServiceImpl_Vtbl
;
2321 return &obj
->IProfferService_iface
;
2324 static HRESULT WINAPI
IServiceProviderImpl_QueryInterface(IServiceProvider
*iface
, REFIID riid
, void **ppvObj
)
2326 IServiceProviderImpl
*This
= impl_from_IServiceProvider(iface
);
2328 if (IsEqualIID(riid
, &IID_IUnknown
) ||
2329 IsEqualIID(riid
, &IID_IServiceProvider
))
2336 IServiceProvider_AddRef(iface
);
2337 /* native uses redefined IID_IServiceProvider symbol, so we can't compare pointers */
2338 if (IsEqualIID(riid
, &IID_IServiceProvider
))
2339 add_call(&trace_got
, 1, iface
, &IID_IServiceProvider
, 0, 0, 0);
2343 return E_NOINTERFACE
;
2346 static ULONG WINAPI
IServiceProviderImpl_AddRef(IServiceProvider
*iface
)
2348 IServiceProviderImpl
*This
= impl_from_IServiceProvider(iface
);
2349 return InterlockedIncrement(&This
->ref
);
2352 static ULONG WINAPI
IServiceProviderImpl_Release(IServiceProvider
*iface
)
2354 IServiceProviderImpl
*This
= impl_from_IServiceProvider(iface
);
2355 ULONG ref
= InterlockedDecrement(&This
->ref
);
2359 HeapFree(GetProcessHeap(), 0, This
);
2365 static HRESULT WINAPI
IServiceProviderImpl_QueryService(
2366 IServiceProvider
*iface
, REFGUID service
, REFIID riid
, void **ppv
)
2368 /* native uses redefined pointer for IID_IOleCommandTarget, not one from uuid.lib */
2369 if (IsEqualIID(riid
, &IID_IOleCommandTarget
))
2371 add_call(&trace_got
, 2, iface
, service
, &IID_IOleCommandTarget
, 0, 0);
2372 *ppv
= IOleCommandTargetImpl_Construct();
2374 if (IsEqualIID(riid
, &IID_IProfferService
))
2376 if (IsEqualIID(service
, &IID_IProfferService
))
2377 add_call(&trace_got
, 2, &IID_IProfferService
, &IID_IProfferService
, 0, 0, 0);
2378 *ppv
= IProfferServiceImpl_Construct();
2383 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl
=
2385 IServiceProviderImpl_QueryInterface
,
2386 IServiceProviderImpl_AddRef
,
2387 IServiceProviderImpl_Release
,
2388 IServiceProviderImpl_QueryService
2391 static void test_IUnknown_QueryServiceExec(void)
2393 IServiceProvider
*provider
;
2394 static const GUID dummy_serviceid
= { 0xdeadbeef };
2395 static const GUID dummy_groupid
= { 0xbeefbeef };
2396 call_trace_t trace_expected
;
2399 /* on <=W2K platforms same ordinal used for another export with different
2400 prototype, so skipping using this indirect condition */
2401 if (is_win2k_and_lower
)
2403 win_skip("IUnknown_QueryServiceExec is not available\n");
2407 provider
= IServiceProviderImpl_Construct();
2409 /* null source pointer */
2410 hr
= pIUnknown_QueryServiceExec(NULL
, &dummy_serviceid
, &dummy_groupid
, 0, 0, 0, 0);
2412 hr
== E_NOTIMPL
, /* win 8 */
2413 "got 0x%08x\n", hr
);
2416 IUnknown_QueryServiceExec( ptr1, serviceid, groupid, arg1, arg2, arg3, arg4);
2417 -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &prov );
2418 -> IServiceProvider_QueryService( prov, serviceid, &IID_IOleCommandTarget, &obj );
2419 -> IOleCommandTarget_Exec( obj, groupid, arg1, arg2, arg3, arg4 );
2421 init_call_trace(&trace_expected
);
2423 add_call(&trace_expected
, 1, provider
, &IID_IServiceProvider
, 0, 0, 0);
2424 add_call(&trace_expected
, 2, provider
, &dummy_serviceid
, &IID_IOleCommandTarget
, 0, 0);
2425 add_call(&trace_expected
, 3, &dummy_groupid
, (void*)0x1, (void*)0x2, (void*)0x3, (void*)0x4);
2427 init_call_trace(&trace_got
);
2428 hr
= pIUnknown_QueryServiceExec((IUnknown
*)provider
, &dummy_serviceid
, &dummy_groupid
, 0x1, 0x2, (void*)0x3, (void*)0x4);
2429 ok(hr
== S_OK
, "got 0x%08x\n", hr
);
2431 ok_trace(&trace_expected
, &trace_got
);
2433 free_call_trace(&trace_expected
);
2434 free_call_trace(&trace_got
);
2436 IServiceProvider_Release(provider
);
2440 static HRESULT WINAPI
IProfferServiceImpl_QueryInterface(IProfferService
*iface
, REFIID riid
, void **ppvObj
)
2442 IProfferServiceImpl
*This
= impl_from_IProfferService(iface
);
2444 if (IsEqualIID(riid
, &IID_IUnknown
) ||
2445 IsEqualIID(riid
, &IID_IProfferService
))
2449 else if (IsEqualIID(riid
, &IID_IServiceProvider
))
2451 *ppvObj
= IServiceProviderImpl_Construct();
2452 add_call(&trace_got
, 1, iface
, &IID_IServiceProvider
, 0, 0, 0);
2458 IProfferService_AddRef(iface
);
2462 return E_NOINTERFACE
;
2465 static ULONG WINAPI
IProfferServiceImpl_AddRef(IProfferService
*iface
)
2467 IProfferServiceImpl
*This
= impl_from_IProfferService(iface
);
2468 return InterlockedIncrement(&This
->ref
);
2471 static ULONG WINAPI
IProfferServiceImpl_Release(IProfferService
*iface
)
2473 IProfferServiceImpl
*This
= impl_from_IProfferService(iface
);
2474 ULONG ref
= InterlockedDecrement(&This
->ref
);
2478 HeapFree(GetProcessHeap(), 0, This
);
2484 static HRESULT WINAPI
IProfferServiceImpl_ProfferService(IProfferService
*iface
,
2485 REFGUID service
, IServiceProvider
*pService
, DWORD
*pCookie
)
2487 *pCookie
= 0xdeadbeef;
2488 add_call(&trace_got
, 3, service
, pService
, pCookie
, 0, 0);
2492 static HRESULT WINAPI
IProfferServiceImpl_RevokeService(IProfferService
*iface
, DWORD cookie
)
2494 add_call(&trace_got
, 4, (void*)(DWORD_PTR
)cookie
, 0, 0, 0, 0);
2498 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl
=
2500 IProfferServiceImpl_QueryInterface
,
2501 IProfferServiceImpl_AddRef
,
2502 IProfferServiceImpl_Release
,
2503 IProfferServiceImpl_ProfferService
,
2504 IProfferServiceImpl_RevokeService
2507 static void test_IUnknown_ProfferService(void)
2509 IServiceProvider
*provider
;
2510 IProfferService
*proff
;
2511 static const GUID dummy_serviceid
= { 0xdeadbeef };
2512 call_trace_t trace_expected
;
2516 /* on <=W2K platforms same ordinal used for another export with different
2517 prototype, so skipping using this indirect condition */
2518 if (is_win2k_and_lower
)
2520 win_skip("IUnknown_ProfferService is not available\n");
2524 provider
= IServiceProviderImpl_Construct();
2525 proff
= IProfferServiceImpl_Construct();
2527 /* null source pointer */
2528 hr
= pIUnknown_ProfferService(NULL
, &dummy_serviceid
, 0, 0);
2530 hr
== E_NOTIMPL
, /* win 8 */
2531 "got 0x%08x\n", hr
);
2534 IUnknown_ProfferService( ptr1, serviceid, arg1, arg2);
2535 -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &provider );
2536 -> IServiceProvider_QueryService( provider, &IID_IProfferService, &IID_IProfferService, &proffer );
2538 if (service pointer not null):
2539 -> IProfferService_ProfferService( proffer, serviceid, arg1, arg2 );
2541 -> IProfferService_RevokeService( proffer, *arg2 );
2543 init_call_trace(&trace_expected
);
2545 add_call(&trace_expected
, 1, proff
, &IID_IServiceProvider
, 0, 0, 0);
2546 add_call(&trace_expected
, 2, &IID_IProfferService
, &IID_IProfferService
, 0, 0, 0);
2547 add_call(&trace_expected
, 3, &dummy_serviceid
, provider
, &cookie
, 0, 0);
2549 init_call_trace(&trace_got
);
2551 hr
= pIUnknown_ProfferService((IUnknown
*)proff
, &dummy_serviceid
, provider
, &cookie
);
2552 ok(hr
== S_OK
, "got 0x%08x\n", hr
);
2553 ok(cookie
== 0xdeadbeef, "got %x\n", cookie
);
2555 ok_trace(&trace_expected
, &trace_got
);
2556 free_call_trace(&trace_got
);
2557 free_call_trace(&trace_expected
);
2559 /* same with ::Revoke path */
2560 init_call_trace(&trace_expected
);
2562 add_call(&trace_expected
, 1, proff
, &IID_IServiceProvider
, 0, 0, 0);
2563 add_call(&trace_expected
, 2, &IID_IProfferService
, &IID_IProfferService
, 0, 0, 0);
2564 add_call(&trace_expected
, 4, (void*)(DWORD_PTR
)cookie
, 0, 0, 0, 0);
2566 init_call_trace(&trace_got
);
2567 ok(cookie
!= 0, "got %x\n", cookie
);
2568 hr
= pIUnknown_ProfferService((IUnknown
*)proff
, &dummy_serviceid
, 0, &cookie
);
2569 ok(hr
== S_OK
, "got 0x%08x\n", hr
);
2570 ok(cookie
== 0, "got %x\n", cookie
);
2571 ok_trace(&trace_expected
, &trace_got
);
2572 free_call_trace(&trace_got
);
2573 free_call_trace(&trace_expected
);
2575 IServiceProvider_Release(provider
);
2576 IProfferService_Release(proff
);
2579 static void test_SHCreateWorkerWindowA(void)
2587 if (is_win2k_and_lower
)
2589 win_skip("SHCreateWorkerWindowA not available\n");
2593 hwnd
= pSHCreateWorkerWindowA(0, NULL
, 0, 0, 0, 0);
2594 ok(hwnd
!= 0, "expected window\n");
2596 GetClassNameA(hwnd
, classA
, 20);
2597 ok(lstrcmpA(classA
, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA
);
2599 ret
= GetWindowLongPtrA(hwnd
, 0);
2600 ok(ret
== 0, "got %ld\n", ret
);
2603 memset(&cliA
, 0, sizeof(cliA
));
2604 res
= GetClassInfoA(GetModuleHandleA("shlwapi.dll"), "WorkerA", &cliA
);
2605 ok(res
, "failed to get class info\n");
2606 ok(cliA
.style
== 0, "got 0x%08x\n", cliA
.style
);
2607 ok(cliA
.cbClsExtra
== 0, "got %d\n", cliA
.cbClsExtra
);
2608 ok(cliA
.cbWndExtra
== sizeof(LONG_PTR
), "got %d\n", cliA
.cbWndExtra
);
2609 ok(cliA
.lpszMenuName
== 0, "got %s\n", cliA
.lpszMenuName
);
2611 DestroyWindow(hwnd
);
2613 /* set extra bytes */
2614 hwnd
= pSHCreateWorkerWindowA(0, NULL
, 0, 0, 0, 0xdeadbeef);
2615 ok(hwnd
!= 0, "expected window\n");
2617 GetClassNameA(hwnd
, classA
, 20);
2618 ok(lstrcmpA(classA
, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA
);
2620 ret
= GetWindowLongPtrA(hwnd
, 0);
2621 ok(ret
== 0xdeadbeef, "got %ld\n", ret
);
2624 ret
= GetWindowLongA(hwnd
, GWL_EXSTYLE
);
2625 ok(ret
== WS_EX_WINDOWEDGE
||
2626 ret
== (WS_EX_WINDOWEDGE
|WS_EX_LAYOUTRTL
) /* systems with RTL locale */, "0x%08lx\n", ret
);
2628 DestroyWindow(hwnd
);
2630 hwnd
= pSHCreateWorkerWindowA(0, NULL
, WS_EX_TOOLWINDOW
, 0, 0, 0);
2631 ret
= GetWindowLongA(hwnd
, GWL_EXSTYLE
);
2632 ok(ret
== (WS_EX_WINDOWEDGE
|WS_EX_TOOLWINDOW
) ||
2633 ret
== (WS_EX_WINDOWEDGE
|WS_EX_TOOLWINDOW
|WS_EX_LAYOUTRTL
) /* systems with RTL locale */, "0x%08lx\n", ret
);
2634 DestroyWindow(hwnd
);
2637 static HRESULT WINAPI
SF_QueryInterface(IShellFolder
*iface
,
2638 REFIID riid
, void **ppv
)
2640 /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */
2641 ok(!IsEqualGUID(&IID_IShellFolder
, riid
),
2642 "Unexpected QI for IShellFolder\n");
2643 return E_NOINTERFACE
;
2646 static ULONG WINAPI
SF_AddRef(IShellFolder
*iface
)
2651 static ULONG WINAPI
SF_Release(IShellFolder
*iface
)
2656 static HRESULT WINAPI
SF_ParseDisplayName(IShellFolder
*iface
,
2657 HWND owner
, LPBC reserved
, LPOLESTR displayName
, ULONG
*eaten
,
2658 LPITEMIDLIST
*idl
, ULONG
*attr
)
2660 ok(0, "Didn't expect ParseDisplayName\n");
2664 static HRESULT WINAPI
SF_EnumObjects(IShellFolder
*iface
,
2665 HWND owner
, SHCONTF flags
, IEnumIDList
**enm
)
2667 *enm
= (IEnumIDList
*)0xcafebabe;
2671 static HRESULT WINAPI
SF_BindToObject(IShellFolder
*iface
,
2672 LPCITEMIDLIST idl
, LPBC reserved
, REFIID riid
, void **obj
)
2674 ok(0, "Didn't expect BindToObject\n");
2678 static HRESULT WINAPI
SF_BindToStorage(IShellFolder
*iface
,
2679 LPCITEMIDLIST idl
, LPBC reserved
, REFIID riid
, void **obj
)
2681 ok(0, "Didn't expect BindToStorage\n");
2685 static HRESULT WINAPI
SF_CompareIDs(IShellFolder
*iface
,
2686 LPARAM lparam
, LPCITEMIDLIST idl1
, LPCITEMIDLIST idl2
)
2688 ok(0, "Didn't expect CompareIDs\n");
2692 static HRESULT WINAPI
SF_CreateViewObject(IShellFolder
*iface
,
2693 HWND owner
, REFIID riid
, void **out
)
2695 ok(0, "Didn't expect CreateViewObject\n");
2699 static HRESULT WINAPI
SF_GetAttributesOf(IShellFolder
*iface
,
2701 UINT cidl
, PCUITEMID_CHILD_ARRAY idl
, SFGAOF
*inOut
)
2703 UINT cidl
, LPCITEMIDLIST
*idl
, SFGAOF
*inOut
)
2706 ok(0, "Didn't expect GetAttributesOf\n");
2710 static HRESULT WINAPI
SF_GetUIObjectOf(IShellFolder
*iface
,
2712 HWND owner
, UINT cidl
, PCUITEMID_CHILD_ARRAY idls
, REFIID riid
, UINT
*inOut
,
2714 HWND owner
, UINT cidl
, LPCITEMIDLIST
*idls
, REFIID riid
, UINT
*inOut
,
2718 ok(0, "Didn't expect GetUIObjectOf\n");
2722 static HRESULT WINAPI
SF_GetDisplayNameOf(IShellFolder
*iface
,
2723 LPCITEMIDLIST idl
, SHGDNF flags
, STRRET
*name
)
2725 ok(0, "Didn't expect GetDisplayNameOf\n");
2729 static HRESULT WINAPI
SF_SetNameOf(IShellFolder
*iface
,
2730 HWND hwnd
, LPCITEMIDLIST idl
, LPCOLESTR name
, SHGDNF flags
,
2731 LPITEMIDLIST
*idlOut
)
2733 ok(0, "Didn't expect SetNameOf\n");
2737 static IShellFolderVtbl ShellFolderVtbl
= {
2741 SF_ParseDisplayName
,
2746 SF_CreateViewObject
,
2749 SF_GetDisplayNameOf
,
2753 static IShellFolder ShellFolder
= { &ShellFolderVtbl
};
2755 static void test_SHIShellFolder_EnumObjects(void)
2759 IShellFolder
*folder
;
2761 if(!pSHIShellFolder_EnumObjects
|| is_win2k_and_lower
){
2762 win_skip("SHIShellFolder_EnumObjects not available\n");
2767 /* NULL object crashes on Windows */
2768 pSHIShellFolder_EnumObjects(NULL
, NULL
, 0, NULL
);
2771 /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */
2772 enm
= (IEnumIDList
*)0xdeadbeef;
2773 hres
= pSHIShellFolder_EnumObjects(&ShellFolder
, NULL
, 0, &enm
);
2774 ok(hres
== S_OK
, "SHIShellFolder_EnumObjects failed: 0x%08x\n", hres
);
2775 ok(enm
== (IEnumIDList
*)0xcafebabe, "Didn't get expected enumerator location, instead: %p\n", enm
);
2777 /* SHIShellFolder_EnumObjects isn't strict about the IShellFolder object */
2778 hres
= pSHGetDesktopFolder(&folder
);
2779 ok(hres
== S_OK
, "SHGetDesktopFolder failed: 0x%08x\n", hres
);
2782 hres
= pSHIShellFolder_EnumObjects(folder
, NULL
, 0, &enm
);
2783 ok(hres
== S_OK
, "SHIShellFolder_EnumObjects failed: 0x%08x\n", hres
);
2784 ok(enm
!= NULL
, "Didn't get an enumerator\n");
2786 IEnumIDList_Release(enm
);
2788 IShellFolder_Release(folder
);
2791 static BOOL
write_inifile(LPCWSTR filename
)
2796 static const char data
[] =
2799 "AnotherKey=asdf\r\n";
2801 file
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
2802 if(file
== INVALID_HANDLE_VALUE
) {
2803 win_skip("failed to create ini file at %s\n", wine_dbgstr_w(filename
));
2807 WriteFile(file
, data
, sizeof(data
), &written
, NULL
);
2814 #define verify_inifile(f, e) r_verify_inifile(__LINE__, f, e)
2815 static void r_verify_inifile(unsigned l
, LPCWSTR filename
, LPCSTR exp
)
2821 file
= CreateFileW(filename
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
2823 if(file
== INVALID_HANDLE_VALUE
)
2826 ReadFile(file
, buf
, sizeof(buf
) * sizeof(CHAR
), &read
, NULL
);
2831 ok_(__FILE__
,l
)(!strcmp(buf
, exp
), "Expected:\n%s\nGot:\n%s\n", exp
,
2835 static void test_SHGetIniString(void)
2838 WCHAR out
[64] = {0};
2840 static const WCHAR TestAppW
[] = {'T','e','s','t','A','p','p',0};
2841 static const WCHAR AKeyW
[] = {'A','K','e','y',0};
2842 static const WCHAR AnotherKeyW
[] = {'A','n','o','t','h','e','r','K','e','y',0};
2843 static const WCHAR JunkKeyW
[] = {'J','u','n','k','K','e','y',0};
2844 static const WCHAR testpathW
[] = {'C',':','\\','t','e','s','t','.','i','n','i',0};
2845 WCHAR pathW
[MAX_PATH
];
2847 if(!pSHGetIniStringW
|| is_win2k_and_lower
){
2848 win_skip("SHGetIniStringW is not available\n");
2852 lstrcpyW(pathW
, testpathW
);
2854 if (!write_inifile(pathW
))
2858 /* these crash on Windows */
2859 pSHGetIniStringW(NULL
, NULL
, NULL
, 0, NULL
);
2860 pSHGetIniStringW(NULL
, AKeyW
, out
, sizeof(out
), pathW
);
2861 pSHGetIniStringW(TestAppW
, AKeyW
, NULL
, sizeof(out
), pathW
);
2864 ret
= pSHGetIniStringW(TestAppW
, AKeyW
, out
, 0, pathW
);
2865 ok(ret
== 0, "SHGetIniStringW should have given 0, instead: %d\n", ret
);
2867 /* valid arguments */
2869 SetLastError(0xdeadbeef);
2870 ret
= pSHGetIniStringW(TestAppW
, NULL
, out
, sizeof(out
), pathW
);
2871 ok(ret
== 4, "SHGetIniStringW should have given 4, instead: %d\n", ret
);
2872 ok(!lstrcmpW(out
, AKeyW
), "Expected %s, got: %s, %d\n",
2873 wine_dbgstr_w(AKeyW
), wine_dbgstr_w(out
), GetLastError());
2875 ret
= pSHGetIniStringW(TestAppW
, AKeyW
, out
, sizeof(out
), pathW
);
2876 ok(ret
== 1, "SHGetIniStringW should have given 1, instead: %d\n", ret
);
2877 ok(!strcmp_wa(out
, "1"), "Expected L\"1\", got: %s\n", wine_dbgstr_w(out
));
2879 ret
= pSHGetIniStringW(TestAppW
, AnotherKeyW
, out
, sizeof(out
), pathW
);
2880 ok(ret
== 4, "SHGetIniStringW should have given 4, instead: %d\n", ret
);
2881 ok(!strcmp_wa(out
, "asdf"), "Expected L\"asdf\", got: %s\n", wine_dbgstr_w(out
));
2884 ret
= pSHGetIniStringW(TestAppW
, JunkKeyW
, out
, sizeof(out
), pathW
);
2885 ok(ret
== 0, "SHGetIniStringW should have given 0, instead: %d\n", ret
);
2886 ok(*out
== 0, "Expected L\"\", got: %s\n", wine_dbgstr_w(out
));
2891 static void test_SHSetIniString(void)
2895 static const WCHAR TestAppW
[] = {'T','e','s','t','A','p','p',0};
2896 static const WCHAR AnotherAppW
[] = {'A','n','o','t','h','e','r','A','p','p',0};
2897 static const WCHAR TestIniW
[] = {'C',':','\\','t','e','s','t','.','i','n','i',0};
2898 static const WCHAR AKeyW
[] = {'A','K','e','y',0};
2899 static const WCHAR NewKeyW
[] = {'N','e','w','K','e','y',0};
2900 static const WCHAR AValueW
[] = {'A','V','a','l','u','e',0};
2902 if(!pSHSetIniStringW
|| is_win2k_and_lower
){
2903 win_skip("SHSetIniStringW is not available\n");
2907 if (!write_inifile(TestIniW
))
2910 ret
= pSHSetIniStringW(TestAppW
, AKeyW
, AValueW
, TestIniW
);
2911 ok(ret
== TRUE
, "SHSetIniStringW should not have failed\n");
2912 todo_wine
/* wine sticks an extra \r\n at the end of the file */
2913 verify_inifile(TestIniW
, "[TestApp]\r\nAKey=AValue\r\nAnotherKey=asdf\r\n");
2915 ret
= pSHSetIniStringW(TestAppW
, AKeyW
, NULL
, TestIniW
);
2916 ok(ret
== TRUE
, "SHSetIniStringW should not have failed\n");
2917 verify_inifile(TestIniW
, "[TestApp]\r\nAnotherKey=asdf\r\n");
2919 ret
= pSHSetIniStringW(AnotherAppW
, NewKeyW
, AValueW
, TestIniW
);
2920 ok(ret
== TRUE
, "SHSetIniStringW should not have failed\n");
2921 verify_inifile(TestIniW
, "[TestApp]\r\nAnotherKey=asdf\r\n[AnotherApp]\r\nNewKey=AValue\r\n");
2923 ret
= pSHSetIniStringW(TestAppW
, NULL
, AValueW
, TestIniW
);
2924 ok(ret
== TRUE
, "SHSetIniStringW should not have failed\n");
2925 verify_inifile(TestIniW
, "[AnotherApp]\r\nNewKey=AValue\r\n");
2927 DeleteFileW(TestIniW
);
2930 enum _shellkey_flags
{
2931 SHKEY_Root_HKCU
= 0x1,
2932 SHKEY_Root_HKLM
= 0x2,
2933 SHKEY_Key_Explorer
= 0x00,
2934 SHKEY_Key_Shell
= 0x10,
2935 SHKEY_Key_ShellNoRoam
= 0x20,
2936 SHKEY_Key_Classes
= 0x30,
2937 SHKEY_Subkey_Default
= 0x0000,
2938 SHKEY_Subkey_ResourceName
= 0x1000,
2939 SHKEY_Subkey_Handlers
= 0x2000,
2940 SHKEY_Subkey_Associations
= 0x3000,
2941 SHKEY_Subkey_Volatile
= 0x4000,
2942 SHKEY_Subkey_MUICache
= 0x5000,
2943 SHKEY_Subkey_FileExts
= 0x6000
2946 static void test_SHGetShellKey(void)
2948 static const WCHAR ShellFoldersW
[] = { 'S','h','e','l','l',' ','F','o','l','d','e','r','s',0 };
2949 static const WCHAR WineTestW
[] = { 'W','i','n','e','T','e','s','t',0 };
2951 void *pPathBuildRootW
= GetProcAddress(hShlwapi
, "PathBuildRootW");
2952 DWORD
*alloc_data
, data
, size
;
2956 if (!pSHGetShellKey
)
2958 win_skip("SHGetShellKey(ordinal 491) isn't available\n");
2963 if (pPathBuildRootW
&& pPathBuildRootW
== pSHGetShellKey
)
2965 win_skip("SHGetShellKey(ordinal 491) used for PathBuildRootW\n");
2969 if (is_win9x
|| is_win2k_and_lower
)
2971 win_skip("Ordinal 491 used for another call, skipping SHGetShellKey tests\n");
2975 /* Vista+ limits SHKEY enumeration values */
2976 SetLastError(0xdeadbeef);
2977 hkey
= pSHGetShellKey(SHKEY_Key_Explorer
, ShellFoldersW
, FALSE
);
2980 /* Tests not working on Vista+ */
2983 hkey
= pSHGetShellKey(SHKEY_Root_HKLM
|SHKEY_Key_Classes
, NULL
, FALSE
);
2984 ok(hkey
!= NULL
, "hkey = NULL\n");
2988 hkey
= pSHGetShellKey(SHKEY_Root_HKCU
|SHKEY_Key_Explorer
, ShellFoldersW
, FALSE
);
2989 ok(hkey
!= NULL
, "hkey = NULL\n");
2992 hkey
= pSHGetShellKey(SHKEY_Root_HKLM
|SHKEY_Key_Explorer
, ShellFoldersW
, FALSE
);
2993 ok(hkey
!= NULL
, "hkey = NULL\n");
2996 hkey
= pSHGetShellKey(SHKEY_Root_HKLM
, WineTestW
, FALSE
);
2997 ok(hkey
== NULL
, "hkey != NULL\n");
2999 hkey
= pSHGetShellKey(SHKEY_Root_HKLM
, NULL
, FALSE
);
3000 ok(hkey
!= NULL
, "Can't open key\n");
3001 ok(SUCCEEDED(RegDeleteKeyW(hkey
, WineTestW
)), "Can't delete key\n");
3004 hkey
= pSHGetShellKey(SHKEY_Root_HKLM
, WineTestW
, TRUE
);
3005 if (!hkey
&& GetLastError() == ERROR_ACCESS_DENIED
)
3007 skip("Not authorized to create keys\n");
3010 ok(hkey
!= NULL
, "Can't create key\n");
3013 if (!pSKGetValueW
|| !pSKSetValueW
|| !pSKDeleteValueW
|| !pSKAllocValueW
)
3015 win_skip("SKGetValueW, SKSetValueW, SKDeleteValueW or SKAllocValueW not available\n");
3019 size
= sizeof(data
);
3020 hres
= pSKGetValueW(SHKEY_Root_HKLM
, WineTestW
, NULL
, NULL
, &data
, &size
);
3021 ok(hres
== HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
), "hres = %x\n", hres
);
3024 hres
= pSKSetValueW(SHKEY_Root_HKLM
, WineTestW
, NULL
, REG_DWORD
, &data
, sizeof(DWORD
));
3025 ok(hres
== S_OK
, "hres = %x\n", hres
);
3028 hres
= pSKGetValueW(SHKEY_Root_HKLM
, WineTestW
, NULL
, NULL
, NULL
, &size
);
3029 ok(hres
== S_OK
, "hres = %x\n", hres
);
3030 ok(size
== sizeof(DWORD
), "size = %d\n", size
);
3033 hres
= pSKGetValueW(SHKEY_Root_HKLM
, WineTestW
, NULL
, NULL
, &data
, &size
);
3034 ok(hres
== S_OK
, "hres = %x\n", hres
);
3035 ok(size
== sizeof(DWORD
), "size = %d\n", size
);
3036 ok(data
== 1234, "data = %d\n", data
);
3038 hres
= pSKAllocValueW(SHKEY_Root_HKLM
, WineTestW
, NULL
, NULL
, (void**)&alloc_data
, &size
);
3039 ok(hres
== S_OK
, "hres= %x\n", hres
);
3040 ok(size
== sizeof(DWORD
), "size = %d\n", size
);
3041 if (SUCCEEDED(hres
))
3043 ok(*alloc_data
== 1234, "*alloc_data = %d\n", *alloc_data
);
3044 LocalFree(alloc_data
);
3047 hres
= pSKDeleteValueW(SHKEY_Root_HKLM
, WineTestW
, NULL
);
3048 ok(hres
== S_OK
, "hres = %x\n", hres
);
3050 hres
= pSKDeleteValueW(SHKEY_Root_HKLM
, WineTestW
, NULL
);
3051 ok(hres
== HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
), "hres = %x\n", hres
);
3053 hres
= pSKGetValueW(SHKEY_Root_HKLM
, WineTestW
, NULL
, NULL
, &data
, &size
);
3054 ok(hres
== HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
), "hres = %x\n", hres
);
3056 hkey
= pSHGetShellKey(SHKEY_Root_HKLM
, NULL
, FALSE
);
3057 ok(hkey
!= NULL
, "Can't create key\n");
3058 ok(SUCCEEDED(RegDeleteKeyW(hkey
, WineTestW
)), "Can't delete key\n");
3062 static void init_pointers(void)
3064 #define MAKEFUNC(f, ord) (p##f = (void*)GetProcAddress(hShlwapi, (LPSTR)(ord)))
3065 MAKEFUNC(SHAllocShared
, 7);
3066 MAKEFUNC(SHLockShared
, 8);
3067 MAKEFUNC(SHUnlockShared
, 9);
3068 MAKEFUNC(SHFreeShared
, 10);
3069 MAKEFUNC(SHMapHandle
, 11);
3070 MAKEFUNC(GetAcceptLanguagesA
, 14);
3071 MAKEFUNC(SHSetWindowBits
, 165);
3072 MAKEFUNC(SHSetParentHwnd
, 167);
3073 MAKEFUNC(ConnectToConnectionPoint
, 168);
3074 MAKEFUNC(IUnknown_GetClassID
, 175);
3075 MAKEFUNC(SHSearchMapInt
, 198);
3076 MAKEFUNC(SHCreateWorkerWindowA
, 257);
3077 MAKEFUNC(GUIDFromStringA
, 269);
3078 MAKEFUNC(SHPackDispParams
, 282);
3079 MAKEFUNC(IConnectionPoint_InvokeWithCancel
, 283);
3080 MAKEFUNC(IConnectionPoint_SimpleInvoke
, 284);
3081 MAKEFUNC(SHGetIniStringW
, 294);
3082 MAKEFUNC(SHSetIniStringW
, 295);
3083 MAKEFUNC(SHFormatDateTimeA
, 353);
3084 MAKEFUNC(SHFormatDateTimeW
, 354);
3085 MAKEFUNC(SHIShellFolder_EnumObjects
, 404);
3086 MAKEFUNC(GetShellSecurityDescriptor
, 475);
3087 MAKEFUNC(SHGetObjectCompatFlags
, 476);
3088 MAKEFUNC(IUnknown_QueryServiceExec
, 484);
3089 MAKEFUNC(SHGetShellKey
, 491);
3090 MAKEFUNC(SHPropertyBag_ReadLONG
, 496);
3091 MAKEFUNC(IUnknown_ProfferService
, 514);
3092 MAKEFUNC(SKGetValueW
, 516);
3093 MAKEFUNC(SKSetValueW
, 517);
3094 MAKEFUNC(SKDeleteValueW
, 518);
3095 MAKEFUNC(SKAllocValueW
, 519);
3098 pDllGetVersion
= (void*)GetProcAddress(hShlwapi
, "DllGetVersion");
3101 static void test_SHSetParentHwnd(void)
3103 HWND hwnd
, hwnd2
, ret
;
3106 if (!pSHSetParentHwnd
)
3108 win_skip("SHSetParentHwnd not available\n");
3112 hwnd
= CreateWindowA("Button", "", WS_VISIBLE
, 0, 0, 10, 10, NULL
, NULL
, NULL
, NULL
);
3113 ok(hwnd
!= NULL
, "got %p\n", hwnd
);
3115 hwnd2
= CreateWindowA("Button", "", WS_VISIBLE
| WS_CHILD
, 0, 0, 10, 10, hwnd
, NULL
, NULL
, NULL
);
3116 ok(hwnd2
!= NULL
, "got %p\n", hwnd2
);
3119 ret
= pSHSetParentHwnd(NULL
, NULL
);
3120 ok(ret
== NULL
, "got %p\n", ret
);
3122 /* set to no parent while already no parent present */
3123 ret
= GetParent(hwnd
);
3124 ok(ret
== NULL
, "got %p\n", ret
);
3125 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
3126 ok((style
& (WS_POPUP
|WS_CHILD
)) == 0, "got style 0x%08x\n", style
);
3127 ret
= pSHSetParentHwnd(hwnd
, NULL
);
3128 ok(ret
== NULL
, "got %p\n", ret
);
3129 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
3130 ok((style
& (WS_POPUP
|WS_CHILD
)) == 0, "got style 0x%08x\n", style
);
3132 /* reset to null parent from not null */
3133 ret
= GetParent(hwnd2
);
3134 ok(ret
== hwnd
, "got %p\n", ret
);
3135 style
= GetWindowLongA(hwnd2
, GWL_STYLE
);
3136 ok((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
, "got style 0x%08x\n", style
);
3137 ret
= pSHSetParentHwnd(hwnd2
, NULL
);
3138 ok(ret
== NULL
, "got %p\n", ret
);
3139 style
= GetWindowLongA(hwnd2
, GWL_STYLE
);
3140 ok((style
& (WS_POPUP
|WS_CHILD
)) == WS_POPUP
, "got style 0x%08x\n", style
);
3141 ret
= GetParent(hwnd2
);
3142 ok(ret
== NULL
, "got %p\n", ret
);
3144 /* set parent back */
3145 style
= GetWindowLongA(hwnd2
, GWL_STYLE
);
3146 SetWindowLongA(hwnd2
, GWL_STYLE
, style
& ~(WS_CHILD
|WS_POPUP
));
3147 style
= GetWindowLongA(hwnd2
, GWL_STYLE
);
3148 ok((style
& (WS_CHILD
|WS_POPUP
)) == 0, "got 0x%08x\n", style
);
3150 ret
= pSHSetParentHwnd(hwnd2
, hwnd
);
3151 todo_wine
ok(ret
== NULL
, "got %p\n", ret
);
3153 style
= GetWindowLongA(hwnd2
, GWL_STYLE
);
3154 ok((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
, "got style 0x%08x\n", style
);
3155 ret
= GetParent(hwnd2
);
3156 ok(ret
== hwnd
, "got %p\n", ret
);
3158 /* try to set same parent again */
3160 style
= GetWindowLongA(hwnd2
, GWL_STYLE
);
3161 SetWindowLongA(hwnd2
, GWL_STYLE
, style
| WS_POPUP
);
3162 ret
= pSHSetParentHwnd(hwnd2
, hwnd
);
3163 todo_wine
ok(ret
== NULL
, "got %p\n", ret
);
3164 style
= GetWindowLongA(hwnd2
, GWL_STYLE
);
3165 ok((style
& (WS_CHILD
|WS_POPUP
)) == WS_CHILD
, "got 0x%08x\n", style
);
3166 ret
= GetParent(hwnd2
);
3167 ok(ret
== hwnd
, "got %p\n", ret
);
3169 /* without WS_POPUP */
3170 style
= GetWindowLongA(hwnd2
, GWL_STYLE
);
3171 SetWindowLongA(hwnd2
, GWL_STYLE
, style
| ~WS_POPUP
);
3172 ret
= pSHSetParentHwnd(hwnd2
, hwnd
);
3173 todo_wine
ok(ret
== hwnd
, "got %p\n", ret
);
3174 style
= GetWindowLongA(hwnd2
, GWL_STYLE
);
3175 ok((style
& (WS_CHILD
|WS_POPUP
)) == WS_CHILD
, "got 0x%08x\n", style
);
3176 ret
= GetParent(hwnd2
);
3177 ok(ret
== hwnd
, "got %p\n", ret
);
3179 DestroyWindow(hwnd
);
3180 DestroyWindow(hwnd2
);
3183 static HRESULT WINAPI
testpersist_QI(IPersist
*iface
, REFIID riid
, void **obj
)
3185 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IPersist
)) {
3187 IPersist_AddRef(iface
);
3192 return E_NOINTERFACE
;
3195 static HRESULT WINAPI
testpersist_QI2(IPersist
*iface
, REFIID riid
, void **obj
)
3197 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IPersistFolder
)) {
3199 IPersist_AddRef(iface
);
3204 return E_NOINTERFACE
;
3207 static ULONG WINAPI
testpersist_AddRef(IPersist
*iface
)
3212 static ULONG WINAPI
testpersist_Release(IPersist
*iface
)
3217 static HRESULT WINAPI
testpersist_GetClassID(IPersist
*iface
, CLSID
*clsid
)
3219 memset(clsid
, 0xab, sizeof(*clsid
));
3223 static IPersistVtbl testpersistvtbl
= {
3226 testpersist_Release
,
3227 testpersist_GetClassID
3230 static IPersistVtbl testpersist2vtbl
= {
3233 testpersist_Release
,
3234 testpersist_GetClassID
3237 static IPersist testpersist
= { &testpersistvtbl
};
3238 static IPersist testpersist2
= { &testpersist2vtbl
};
3240 static void test_IUnknown_GetClassID(void)
3242 CLSID clsid
, clsid2
, clsid3
;
3245 if (0) /* crashes on native systems */
3246 hr
= pIUnknown_GetClassID(NULL
, NULL
);
3248 memset(&clsid
, 0xcc, sizeof(clsid
));
3249 memset(&clsid3
, 0xcc, sizeof(clsid3
));
3250 hr
= pIUnknown_GetClassID(NULL
, &clsid
);
3251 ok(hr
== E_FAIL
, "got 0x%08x\n", hr
);
3252 ok(IsEqualCLSID(&clsid
, &CLSID_NULL
) || broken(IsEqualCLSID(&clsid
, &clsid3
)) /* win2k, winxp, win2k3 */,
3253 "got wrong clsid %s\n", wine_dbgstr_guid(&clsid
));
3255 memset(&clsid
, 0xcc, sizeof(clsid
));
3256 memset(&clsid2
, 0xab, sizeof(clsid2
));
3257 hr
= pIUnknown_GetClassID((IUnknown
*)&testpersist
, &clsid
);
3258 ok(hr
== 0x8fff2222, "got 0x%08x\n", hr
);
3259 ok(IsEqualCLSID(&clsid
, &clsid2
) || broken(IsEqualCLSID(&clsid
, &clsid3
)) /* win2k3 */,
3260 "got wrong clsid %s\n", wine_dbgstr_guid(&clsid
));
3262 /* IPersistFolder is also supported */
3263 memset(&clsid
, 0xcc, sizeof(clsid
));
3264 memset(&clsid2
, 0xab, sizeof(clsid2
));
3265 memset(&clsid3
, 0xcc, sizeof(clsid3
));
3266 hr
= pIUnknown_GetClassID((IUnknown
*)&testpersist2
, &clsid
);
3267 ok(hr
== 0x8fff2222, "got 0x%08x\n", hr
);
3268 ok(IsEqualCLSID(&clsid
, &clsid2
) || broken(IsEqualCLSID(&clsid
, &clsid3
)) /* win2k3 */,
3269 "got wrong clsid %s\n", wine_dbgstr_guid(&clsid
));
3272 static void test_DllGetVersion(void)
3276 hr
= pDllGetVersion(NULL
);
3277 ok(hr
== E_INVALIDARG
, "got 0x%08x\n", hr
);
3285 hShlwapi
= GetModuleHandleA("shlwapi.dll");
3286 is_win2k_and_lower
= GetProcAddress(hShlwapi
, "StrChrNW") == 0;
3287 is_win9x
= GetProcAddress(hShlwapi
, (LPSTR
)99) == 0; /* StrCpyNXA */
3289 /* SHCreateStreamOnFileEx was introduced in shlwapi v6.0 */
3290 if(!GetProcAddress(hShlwapi
, "SHCreateStreamOnFileEx")){
3291 win_skip("Too old shlwapi version\n");
3297 argc
= winetest_get_mainargs(&argv
);
3302 sscanf(argv
[2], "%d", &procid
);
3303 sscanf(argv
[3], "%p", &hmem
);
3304 test_alloc_shared_remote(procid
, hmem
);
3308 hmlang
= LoadLibraryA("mlang.dll");
3309 pLcidToRfc1766A
= (void *)GetProcAddress(hmlang
, "LcidToRfc1766A");
3311 hshell32
= LoadLibraryA("shell32.dll");
3312 pSHGetDesktopFolder
= (void *)GetProcAddress(hshell32
, "SHGetDesktopFolder");
3314 test_GetAcceptLanguagesA();
3315 test_SHSearchMapInt();
3316 test_alloc_shared(argc
, argv
);
3318 test_GetShellSecurityDescriptor();
3319 test_SHPackDispParams();
3320 test_IConnectionPoint();
3321 test_SHPropertyBag_ReadLONG();
3322 test_SHSetWindowBits();
3323 test_SHFormatDateTimeA();
3324 test_SHFormatDateTimeW();
3325 test_SHGetObjectCompatFlags();
3326 test_IUnknown_QueryServiceExec();
3327 test_IUnknown_ProfferService();
3328 test_SHCreateWorkerWindowA();
3329 test_SHIShellFolder_EnumObjects();
3330 test_SHGetIniString();
3331 test_SHSetIniString();
3332 test_SHGetShellKey();
3333 test_SHSetParentHwnd();
3334 test_IUnknown_GetClassID();
3335 test_DllGetVersion();
3337 FreeLibrary(hshell32
);
3338 FreeLibrary(hmlang
);