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
*);
80 static HMODULE hmlang
;
81 static HRESULT (WINAPI
*pLcidToRfc1766A
)(LCID
, LPSTR
, INT
);
83 static HMODULE hshell32
;
84 static HRESULT (WINAPI
*pSHGetDesktopFolder
)(IShellFolder
**);
86 static const CHAR ie_international
[] = {
87 'S','o','f','t','w','a','r','e','\\',
88 'M','i','c','r','o','s','o','f','t','\\',
89 'I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r','\\',
90 'I','n','t','e','r','n','a','t','i','o','n','a','l',0};
91 static const CHAR acceptlanguage
[] = {
92 'A','c','c','e','p','t','L','a','n','g','u','a','g','e',0};
94 static int strcmp_wa(LPCWSTR strw
, const char *stra
)
97 WideCharToMultiByte(CP_ACP
, 0, strw
, -1, buf
, sizeof(buf
), NULL
, NULL
);
98 return lstrcmpA(stra
, buf
);
112 static void init_call_trace(call_trace_t
*ctrace
)
116 ctrace
->calls
= HeapAlloc(GetProcessHeap(), 0, sizeof(call_entry_t
) * ctrace
->alloc
);
119 static void free_call_trace(const call_trace_t
*ctrace
)
121 HeapFree(GetProcessHeap(), 0, ctrace
->calls
);
124 static void add_call(call_trace_t
*ctrace
, int id
, const void *arg0
,
125 const void *arg1
, const void *arg2
, const void *arg3
, const void *arg4
)
136 if (ctrace
->count
== ctrace
->alloc
)
139 ctrace
->calls
= HeapReAlloc(GetProcessHeap(),0, ctrace
->calls
, ctrace
->alloc
*sizeof(call_entry_t
));
142 ctrace
->calls
[ctrace
->count
++] = call
;
145 static void ok_trace_(call_trace_t
*texpected
, call_trace_t
*tgot
, int line
)
147 if (texpected
->count
== tgot
->count
)
151 for (i
= 0; i
< texpected
->count
; i
++)
153 call_entry_t
*expected
= &texpected
->calls
[i
];
154 call_entry_t
*got
= &tgot
->calls
[i
];
157 ok_(__FILE__
, line
)(expected
->id
== got
->id
, "got different ids %d: %d, %d\n", i
+1, expected
->id
, got
->id
);
159 for (j
= 0; j
< 5; j
++)
161 ok_(__FILE__
, line
)(expected
->args
[j
] == got
->args
[j
], "got different args[%d] for %d: %p, %p\n", j
, i
+1,
162 expected
->args
[j
], got
->args
[j
]);
167 ok_(__FILE__
, line
)(0, "traces length mismatch\n");
170 #define ok_trace(a, b) ok_trace_(a, b, __LINE__)
172 /* trace of actually made calls */
173 static call_trace_t trace_got
;
175 static void test_GetAcceptLanguagesA(void)
177 static LPCSTR table
[] = {"de,en-gb;q=0.7,en;q=0.3",
178 "de,en;q=0.3,en-gb;q=0.7", /* sorting is ignored */
179 "winetest", /* content is ignored */
189 LONG res_query
= ERROR_SUCCESS
;
192 DWORD maxlen
= sizeof(buffer
) - 2;
198 if (!pGetAcceptLanguagesA
) {
199 win_skip("GetAcceptLanguagesA is not available\n");
203 lcid
= GetUserDefaultLCID();
205 /* Get the original Value */
206 lres
= RegOpenKeyA(HKEY_CURRENT_USER
, ie_international
, &hroot
);
208 skip("RegOpenKey(%s) failed: %d\n", ie_international
, lres
);
211 len
= sizeof(original
);
213 res_query
= RegQueryValueExA(hroot
, acceptlanguage
, 0, NULL
, (PBYTE
)original
, &len
);
215 RegDeleteValueA(hroot
, acceptlanguage
);
217 /* Some windows versions use "lang-COUNTRY" as default */
218 memset(language
, 0, sizeof(language
));
219 len
= GetLocaleInfoA(lcid
, LOCALE_SISO639LANGNAME
, language
, sizeof(language
));
222 lstrcatA(language
, "-");
223 memset(buffer
, 0, sizeof(buffer
));
224 len
= GetLocaleInfoA(lcid
, LOCALE_SISO3166CTRYNAME
, buffer
, sizeof(buffer
) - len
- 1);
225 lstrcatA(language
, buffer
);
229 /* LOCALE_SNAME has additional parts in some languages. Try only as last chance */
230 memset(language
, 0, sizeof(language
));
231 len
= GetLocaleInfoA(lcid
, LOCALE_SNAME
, language
, sizeof(language
));
234 /* get the default value */
236 memset(buffer
, '#', maxlen
);
238 hr
= pGetAcceptLanguagesA( buffer
, &len
);
241 win_skip("GetAcceptLanguagesA failed with 0x%x\n", hr
);
242 goto restore_original
;
245 if (lstrcmpA(buffer
, language
)) {
246 /* some windows versions use "lang" or "lang-country" as default */
248 if (pLcidToRfc1766A
) {
249 hr
= pLcidToRfc1766A(lcid
, language
, sizeof(language
));
250 ok(hr
== S_OK
, "LcidToRfc1766A returned 0x%x and %s\n", hr
, language
);
254 ok(!lstrcmpA(buffer
, language
),
255 "have '%s' (searching for '%s')\n", language
, buffer
);
257 if (lstrcmpA(buffer
, language
)) {
258 win_skip("no more ideas, how to build the default language '%s'\n", buffer
);
259 goto restore_original
;
262 trace("detected default: %s\n", language
);
263 while ((entry
= table
[i
])) {
265 exactsize
= lstrlenA(entry
);
267 lres
= RegSetValueExA(hroot
, acceptlanguage
, 0, REG_SZ
, (const BYTE
*) entry
, exactsize
+ 1);
268 ok(!lres
, "got %d for RegSetValueExA: %s\n", lres
, entry
);
270 /* len includes space for the terminating 0 before vista/w2k8 */
272 memset(buffer
, '#', maxlen
);
274 hr
= pGetAcceptLanguagesA( buffer
, &len
);
275 ok(((hr
== E_INVALIDARG
) && (len
== 0)) ||
277 ((len
== exactsize
) || (len
== exactsize
+1)) &&
278 !lstrcmpA(buffer
, entry
)),
279 "+2_#%d: got 0x%x with %d and %s\n", i
, hr
, len
, buffer
);
282 memset(buffer
, '#', maxlen
);
284 hr
= pGetAcceptLanguagesA( buffer
, &len
);
285 ok(((hr
== E_INVALIDARG
) && (len
== 0)) ||
287 ((len
== exactsize
) || (len
== exactsize
+1)) &&
288 !lstrcmpA(buffer
, entry
)),
289 "+1_#%d: got 0x%x with %d and %s\n", i
, hr
, len
, buffer
);
292 memset(buffer
, '#', maxlen
);
294 hr
= pGetAcceptLanguagesA( buffer
, &len
);
296 /* There is no space for the string in the registry.
297 When the buffer is large enough, the default language is returned
299 When the buffer is too small for that fallback, win7_32 and w2k8_64
300 fail with E_NOT_SUFFICIENT_BUFFER, win8 fails with HRESULT_FROM_WIN32(ERROR_MORE_DATA),
301 other versions succeed and return a partial result while older os succeed
302 and overflow the buffer */
304 ok(((hr
== E_INVALIDARG
) && (len
== 0)) ||
305 (((hr
== S_OK
) && !lstrcmpA(buffer
, language
) && (len
== lstrlenA(language
))) ||
306 ((hr
== S_OK
) && !memcmp(buffer
, language
, len
)) ||
307 ((hr
== E_NOT_SUFFICIENT_BUFFER
) && !len
) ||
308 ((hr
== __HRESULT_FROM_WIN32(ERROR_MORE_DATA
)) && len
== exactsize
)),
309 "==_#%d: got 0x%x with %d and %s\n", i
, hr
, len
, buffer
);
313 memset(buffer
, '#', maxlen
);
315 hr
= pGetAcceptLanguagesA( buffer
, &len
);
316 ok(((hr
== E_INVALIDARG
) && (len
== 0)) ||
317 (((hr
== S_OK
) && !lstrcmpA(buffer
, language
) && (len
== lstrlenA(language
))) ||
318 ((hr
== S_OK
) && !memcmp(buffer
, language
, len
)) ||
319 ((hr
== E_NOT_SUFFICIENT_BUFFER
) && !len
) ||
320 ((hr
== __HRESULT_FROM_WIN32(ERROR_MORE_DATA
)) && len
== exactsize
- 1)),
321 "-1_#%d: got 0x%x with %d and %s\n", i
, hr
, len
, buffer
);
325 memset(buffer
, '#', maxlen
);
327 hr
= pGetAcceptLanguagesA( buffer
, &len
);
328 ok(((hr
== E_INVALIDARG
) && (len
== 0)) ||
329 (((hr
== S_OK
) && !lstrcmpA(buffer
, language
) && (len
== lstrlenA(language
))) ||
330 ((hr
== S_OK
) && !memcmp(buffer
, language
, len
)) ||
331 ((hr
== E_NOT_SUFFICIENT_BUFFER
) && !len
) ||
332 ((hr
== __HRESULT_FROM_WIN32(ERROR_MORE_DATA
)) && len
== 1)),
333 "=1_#%d: got 0x%x with %d and %s\n", i
, hr
, len
, buffer
);
336 hr
= pGetAcceptLanguagesA( NULL
, &len
);
338 /* w2k3 and below: E_FAIL and untouched len,
339 since w2k8: S_OK and needed size (excluding 0), win8 S_OK and size including 0. */
340 ok( ((hr
== S_OK
) && ((len
== exactsize
) || (len
== exactsize
+ 1))) ||
341 ((hr
== E_FAIL
) && (len
== maxlen
)),
342 "NULL,max #%d: got 0x%x with %d and %s\n", i
, hr
, len
, buffer
);
347 /* without a value in the registry, a default language is returned */
348 RegDeleteValueA(hroot
, acceptlanguage
);
351 memset(buffer
, '#', maxlen
);
353 hr
= pGetAcceptLanguagesA( buffer
, &len
);
354 ok( ((hr
== S_OK
) && (len
== lstrlenA(language
))),
355 "max: got 0x%x with %d and %s (expected S_OK with %d and '%s'\n",
356 hr
, len
, buffer
, lstrlenA(language
), language
);
359 memset(buffer
, '#', maxlen
);
361 hr
= pGetAcceptLanguagesA( buffer
, &len
);
362 ok( (((hr
== S_OK
) || (hr
== E_INVALIDARG
)) && !memcmp(buffer
, language
, len
)) ||
363 ((hr
== E_NOT_SUFFICIENT_BUFFER
) && !len
) ||
364 ((hr
== __HRESULT_FROM_WIN32(ERROR_CANNOT_COPY
)) && !len
),
365 "=2: got 0x%x with %d and %s\n", hr
, len
, buffer
);
368 memset(buffer
, '#', maxlen
);
370 hr
= pGetAcceptLanguagesA( buffer
, &len
);
371 /* When the buffer is too small, win7_32 and w2k8_64 and above fail with
372 E_NOT_SUFFICIENT_BUFFER, win8 ERROR_CANNOT_COPY,
373 other versions succeed and return a partial 0 terminated result while other versions
374 fail with E_INVALIDARG and return a partial unterminated result */
375 ok( (((hr
== S_OK
) || (hr
== E_INVALIDARG
)) && !memcmp(buffer
, language
, len
)) ||
376 ((hr
== E_NOT_SUFFICIENT_BUFFER
) && !len
) ||
377 ((hr
== __HRESULT_FROM_WIN32(ERROR_CANNOT_COPY
)) && !len
),
378 "=1: got 0x%x with %d and %s\n", hr
, len
, buffer
);
381 memset(buffer
, '#', maxlen
);
383 hr
= pGetAcceptLanguagesA( buffer
, &len
);
384 /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG, win8 ERROR_CANNOT_COPY */
385 ok((hr
== E_FAIL
) || (hr
== E_INVALIDARG
) || (hr
== __HRESULT_FROM_WIN32(ERROR_CANNOT_COPY
)),
388 memset(buffer
, '#', maxlen
);
390 hr
= pGetAcceptLanguagesA( buffer
, NULL
);
391 /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG */
392 ok((hr
== E_FAIL
) || (hr
== E_INVALIDARG
),
393 "got 0x%x (expected E_FAIL or E_INVALIDARG)\n", hr
);
396 hr
= pGetAcceptLanguagesA( NULL
, NULL
);
397 /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG */
398 ok((hr
== E_FAIL
) || (hr
== E_INVALIDARG
),
399 "got 0x%x (expected E_FAIL or E_INVALIDARG)\n", hr
);
403 len
= lstrlenA(original
);
404 lres
= RegSetValueExA(hroot
, acceptlanguage
, 0, REG_SZ
, (const BYTE
*) original
, len
? len
+ 1: 0);
405 ok(!lres
, "RegSetValueEx(%s) failed: %d\n", original
, lres
);
409 RegDeleteValueA(hroot
, acceptlanguage
);
414 static void test_SHSearchMapInt(void)
416 int keys
[8], values
[8];
419 if (!pSHSearchMapInt
)
422 memset(keys
, 0, sizeof(keys
));
423 memset(values
, 0, sizeof(values
));
424 keys
[0] = 99; values
[0] = 101;
426 /* NULL key/value lists crash native, so skip testing them */
429 i
= pSHSearchMapInt(keys
, values
, 1, keys
[0]);
430 ok(i
== values
[0], "Len 1, expected %d, got %d\n", values
[0], i
);
432 /* Key doesn't exist */
433 i
= pSHSearchMapInt(keys
, values
, 1, 100);
434 ok(i
== -1, "Len 1 - bad key, expected -1, got %d\n", i
);
436 /* Len = 0 => not found */
437 i
= pSHSearchMapInt(keys
, values
, 0, keys
[0]);
438 ok(i
== -1, "Len 1 - passed len 0, expected -1, got %d\n", i
);
440 /* 2 elements, len = 1 */
441 keys
[1] = 98; values
[1] = 102;
442 i
= pSHSearchMapInt(keys
, values
, 1, keys
[1]);
443 ok(i
== -1, "Len 1 - array len 2, expected -1, got %d\n", i
);
445 /* 2 elements, len = 2 */
446 i
= pSHSearchMapInt(keys
, values
, 2, keys
[1]);
447 ok(i
== values
[1], "Len 2, expected %d, got %d\n", values
[1], i
);
449 /* Searches forward */
450 keys
[2] = 99; values
[2] = 103;
451 i
= pSHSearchMapInt(keys
, values
, 3, keys
[0]);
452 ok(i
== values
[0], "Len 3, expected %d, got %d\n", values
[0], i
);
461 static void test_alloc_shared(int argc
, char **argv
)
463 char cmdline
[MAX_PATH
];
464 PROCESS_INFORMATION pi
;
465 STARTUPINFOA si
= { 0 };
467 HANDLE hmem
, hmem2
= 0;
468 struct shared_struct val
, *p
;
471 procid
=GetCurrentProcessId();
472 hmem
=pSHAllocShared(NULL
,10,procid
);
473 ok(hmem
!=NULL
,"SHAllocShared(NULL...) failed: %u\n", GetLastError());
474 ret
= pSHFreeShared(hmem
, procid
);
475 ok( ret
, "SHFreeShared failed: %u\n", GetLastError());
477 val
.value
= 0x12345678;
479 hmem
= pSHAllocShared(&val
, sizeof(val
), procid
);
480 ok(hmem
!=NULL
,"SHAllocShared(NULL...) failed: %u\n", GetLastError());
482 p
=pSHLockShared(hmem
,procid
);
483 ok(p
!=NULL
,"SHLockShared failed: %u\n", GetLastError());
485 ok(p
->value
== 0x12345678, "Wrong value in shared memory: %d instead of %d\n", p
->value
, 0x12345678);
486 ret
= pSHUnlockShared(p
);
487 ok( ret
, "SHUnlockShared failed: %u\n", GetLastError());
489 sprintf(cmdline
, "%s %s %d %p", argv
[0], argv
[1], procid
, hmem
);
490 ret
= CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
491 ok(ret
, "could not create child process error: %u\n", GetLastError());
494 winetest_wait_child_process(pi
.hProcess
);
495 CloseHandle(pi
.hThread
);
496 CloseHandle(pi
.hProcess
);
498 p
= pSHLockShared(hmem
, procid
);
499 ok(p
!= NULL
,"SHLockShared failed: %u\n", GetLastError());
500 if (p
!= NULL
&& p
->value
!= 0x12345678)
502 ok(p
->value
== 0x12345679, "Wrong value in shared memory: %d instead of %d\n", p
->value
, 0x12345679);
504 ok(hmem2
!= NULL
, "Expected handle in shared memory\n");
506 ret
= pSHUnlockShared(p
);
507 ok(ret
, "SHUnlockShared failed: %u\n", GetLastError());
510 ret
= pSHFreeShared(hmem
, procid
);
511 ok( ret
, "SHFreeShared failed: %u\n", GetLastError());
515 p
= pSHLockShared(hmem2
, procid
);
516 ok(p
!= NULL
,"SHLockShared failed: %u\n", GetLastError());
518 ok(p
->value
== 0xDEADBEEF, "Wrong value in shared memory: %d instead of %d\n", p
->value
, 0xDEADBEEF);
519 ret
= pSHUnlockShared(p
);
520 ok(ret
, "SHUnlockShared failed: %u\n", GetLastError());
522 ret
= pSHFreeShared(hmem2
, procid
);
523 ok(ret
, "SHFreeShared failed: %u\n", GetLastError());
527 static void test_alloc_shared_remote(DWORD procid
, HANDLE hmem
)
529 struct shared_struct val
, *p
;
533 /* test directly accessing shared memory of a remote process */
534 p
= pSHLockShared(hmem
, procid
);
535 ok(p
!= NULL
|| broken(p
== NULL
) /* Windows 7/8 */, "SHLockShared failed: %u\n", GetLastError());
538 win_skip("Subprocess failed to modify shared memory, skipping test\n");
542 ok(p
->value
== 0x12345678, "Wrong value in shared memory: %d instead of %d\n", p
->value
, 0x12345678);
545 val
.value
= 0xDEADBEEF;
547 p
->handle
= pSHAllocShared(&val
, sizeof(val
), procid
);
548 ok(p
->handle
!= NULL
, "SHAllocShared failed: %u\n", GetLastError());
550 ret
= pSHUnlockShared(p
);
551 ok(ret
, "SHUnlockShared failed: %u\n", GetLastError());
553 /* test SHMapHandle */
554 hmem2
= pSHMapHandle(hmem
, procid
, GetCurrentProcessId(), 0, 0);
556 /* It seems like Windows Vista/2008 uses a different internal implementation
557 * for shared memory, and calling SHMapHandle fails. */
558 ok(hmem2
!= NULL
|| broken(hmem2
== NULL
),
559 "SHMapHandle failed: %u\n", GetLastError());
562 win_skip("Subprocess failed to map shared memory, skipping test\n");
566 p
= pSHLockShared(hmem2
, GetCurrentProcessId());
567 ok(p
!= NULL
, "SHLockShared failed: %u\n", GetLastError());
570 ok(p
->value
== 0x12345679, "Wrong value in shared memory: %d instead of %d\n", p
->value
, 0x12345679);
572 ret
= pSHUnlockShared(p
);
573 ok(ret
, "SHUnlockShared failed: %u\n", GetLastError());
575 ret
= pSHFreeShared(hmem2
, GetCurrentProcessId());
576 ok(ret
, "SHFreeShared failed: %u\n", GetLastError());
579 static void test_fdsa(void)
583 DWORD num_items
; /* Number of elements inserted */
584 void *mem
; /* Ptr to array */
585 DWORD blocks_alloced
; /* Number of elements allocated */
586 BYTE inc
; /* Number of elements to grow by when we need to expand */
587 BYTE block_size
; /* Size in bytes of an element */
588 BYTE flags
; /* Flags */
591 BOOL (WINAPI
*pFDSA_Initialize
)(DWORD block_size
, DWORD inc
, FDSA_info
*info
, void *mem
,
593 BOOL (WINAPI
*pFDSA_Destroy
)(FDSA_info
*info
);
594 DWORD (WINAPI
*pFDSA_InsertItem
)(FDSA_info
*info
, DWORD where
, const void *block
);
595 BOOL (WINAPI
*pFDSA_DeleteItem
)(FDSA_info
*info
, DWORD where
);
598 int block_size
= 10, init_blocks
= 4, inc
= 2;
602 pFDSA_Initialize
= (void *)GetProcAddress(hShlwapi
, (LPSTR
)208);
603 pFDSA_Destroy
= (void *)GetProcAddress(hShlwapi
, (LPSTR
)209);
604 pFDSA_InsertItem
= (void *)GetProcAddress(hShlwapi
, (LPSTR
)210);
605 pFDSA_DeleteItem
= (void *)GetProcAddress(hShlwapi
, (LPSTR
)211);
607 mem
= HeapAlloc(GetProcessHeap(), 0, block_size
* init_blocks
);
608 memset(&info
, 0, sizeof(info
));
610 ok(pFDSA_Initialize(block_size
, inc
, &info
, mem
, init_blocks
), "FDSA_Initialize rets FALSE\n");
611 ok(info
.num_items
== 0, "num_items = %d\n", info
.num_items
);
612 ok(info
.mem
== mem
, "mem = %p\n", info
.mem
);
613 ok(info
.blocks_alloced
== init_blocks
, "blocks_alloced = %d\n", info
.blocks_alloced
);
614 ok(info
.inc
== inc
, "inc = %d\n", info
.inc
);
615 ok(info
.block_size
== block_size
, "block_size = %d\n", info
.block_size
);
616 ok(info
.flags
== 0, "flags = %d\n", info
.flags
);
618 ret
= pFDSA_InsertItem(&info
, 1234, "1234567890");
619 ok(ret
== 0, "ret = %d\n", ret
);
620 ok(info
.num_items
== 1, "num_items = %d\n", info
.num_items
);
621 ok(info
.mem
== mem
, "mem = %p\n", info
.mem
);
622 ok(info
.blocks_alloced
== init_blocks
, "blocks_alloced = %d\n", info
.blocks_alloced
);
623 ok(info
.inc
== inc
, "inc = %d\n", info
.inc
);
624 ok(info
.block_size
== block_size
, "block_size = %d\n", info
.block_size
);
625 ok(info
.flags
== 0, "flags = %d\n", info
.flags
);
627 ret
= pFDSA_InsertItem(&info
, 1234, "abcdefghij");
628 ok(ret
== 1, "ret = %d\n", ret
);
630 ret
= pFDSA_InsertItem(&info
, 1, "klmnopqrst");
631 ok(ret
== 1, "ret = %d\n", ret
);
633 ret
= pFDSA_InsertItem(&info
, 0, "uvwxyzABCD");
634 ok(ret
== 0, "ret = %d\n", ret
);
635 ok(info
.mem
== mem
, "mem = %p\n", info
.mem
);
636 ok(info
.flags
== 0, "flags = %d\n", info
.flags
);
638 /* This next InsertItem will cause shlwapi to allocate its own mem buffer */
639 ret
= pFDSA_InsertItem(&info
, 0, "EFGHIJKLMN");
640 ok(ret
== 0, "ret = %d\n", ret
);
641 ok(info
.mem
!= mem
, "mem = %p\n", info
.mem
);
642 ok(info
.blocks_alloced
== init_blocks
+ inc
, "blocks_alloced = %d\n", info
.blocks_alloced
);
643 ok(info
.flags
== 0x1, "flags = %d\n", info
.flags
);
645 ok(!memcmp(info
.mem
, "EFGHIJKLMNuvwxyzABCD1234567890klmnopqrstabcdefghij", 50), "mem %s\n", (char*)info
.mem
);
647 ok(pFDSA_DeleteItem(&info
, 2), "rets FALSE\n");
648 ok(info
.mem
!= mem
, "mem = %p\n", info
.mem
);
649 ok(info
.blocks_alloced
== init_blocks
+ inc
, "blocks_alloced = %d\n", info
.blocks_alloced
);
650 ok(info
.flags
== 0x1, "flags = %d\n", info
.flags
);
652 ok(!memcmp(info
.mem
, "EFGHIJKLMNuvwxyzABCDklmnopqrstabcdefghij", 40), "mem %s\n", (char*)info
.mem
);
654 ok(pFDSA_DeleteItem(&info
, 3), "rets FALSE\n");
655 ok(info
.mem
!= mem
, "mem = %p\n", info
.mem
);
656 ok(info
.blocks_alloced
== init_blocks
+ inc
, "blocks_alloced = %d\n", info
.blocks_alloced
);
657 ok(info
.flags
== 0x1, "flags = %d\n", info
.flags
);
659 ok(!memcmp(info
.mem
, "EFGHIJKLMNuvwxyzABCDklmnopqrst", 30), "mem %s\n", (char*)info
.mem
);
661 ok(!pFDSA_DeleteItem(&info
, 4), "does not ret FALSE\n");
663 /* As shlwapi has allocated memory internally, Destroy will ret FALSE */
664 ok(!pFDSA_Destroy(&info
), "FDSA_Destroy does not ret FALSE\n");
667 /* When Initialize is called with inc = 0, set it to 1 */
668 ok(pFDSA_Initialize(block_size
, 0, &info
, mem
, init_blocks
), "FDSA_Initialize rets FALSE\n");
669 ok(info
.inc
== 1, "inc = %d\n", info
.inc
);
671 /* This time, because shlwapi hasn't had to allocate memory
672 internally, Destroy rets non-zero */
673 ok(pFDSA_Destroy(&info
), "FDSA_Destroy rets FALSE\n");
676 HeapFree(GetProcessHeap(), 0, mem
);
680 typedef struct SHELL_USER_SID
{
681 SID_IDENTIFIER_AUTHORITY sidAuthority
;
684 } SHELL_USER_SID
, *PSHELL_USER_SID
;
685 typedef struct SHELL_USER_PERMISSION
{
686 SHELL_USER_SID susID
;
691 DWORD dwInheritAccessMask
;
692 } SHELL_USER_PERMISSION
, *PSHELL_USER_PERMISSION
;
693 static void test_GetShellSecurityDescriptor(void)
695 SHELL_USER_PERMISSION supCurrentUserFull
= {
696 { {SECURITY_NULL_SID_AUTHORITY
}, 0, 0 },
697 ACCESS_ALLOWED_ACE_TYPE
, FALSE
,
699 #define MY_INHERITANCE 0xBE /* invalid value to proof behavior */
700 SHELL_USER_PERMISSION supEveryoneDenied
= {
701 { {SECURITY_WORLD_SID_AUTHORITY
}, SECURITY_WORLD_RID
, 0 },
702 ACCESS_DENIED_ACE_TYPE
, TRUE
,
703 GENERIC_WRITE
, MY_INHERITANCE
| 0xDEADBA00, GENERIC_READ
};
704 PSHELL_USER_PERMISSION rgsup
[2] = {
705 &supCurrentUserFull
, &supEveryoneDenied
,
707 SECURITY_DESCRIPTOR
* psd
;
708 SECURITY_DESCRIPTOR
* (WINAPI
*pGetShellSecurityDescriptor
)(PSHELL_USER_PERMISSION
*,int);
709 void *pChrCmpIW
= GetProcAddress(hShlwapi
, "ChrCmpIW");
711 pGetShellSecurityDescriptor
=(void*)GetProcAddress(hShlwapi
,(char*)475);
713 if(!pGetShellSecurityDescriptor
)
715 win_skip("GetShellSecurityDescriptor not available\n");
719 if(pChrCmpIW
&& pChrCmpIW
== pGetShellSecurityDescriptor
) /* win2k */
721 win_skip("Skipping for GetShellSecurityDescriptor, same ordinal used for ChrCmpIW\n");
725 psd
= pGetShellSecurityDescriptor(NULL
, 2);
727 broken(psd
==INVALID_HANDLE_VALUE
), /* IE5 */
728 "GetShellSecurityDescriptor should fail\n");
729 psd
= pGetShellSecurityDescriptor(rgsup
, 0);
730 ok(psd
==NULL
, "GetShellSecurityDescriptor should fail, got %p\n", psd
);
732 SetLastError(0xdeadbeef);
733 psd
= pGetShellSecurityDescriptor(rgsup
, 2);
734 if (psd
== NULL
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
736 /* The previous calls to GetShellSecurityDescriptor don't set the last error */
737 win_skip("GetShellSecurityDescriptor is not implemented\n");
740 if (psd
== INVALID_HANDLE_VALUE
)
742 win_skip("GetShellSecurityDescriptor is broken on IE5\n");
745 ok(psd
!=NULL
, "GetShellSecurityDescriptor failed\n");
748 BOOL bHasDacl
= FALSE
, bDefaulted
, ret
;
751 SECURITY_DESCRIPTOR_CONTROL control
;
753 ok(IsValidSecurityDescriptor(psd
), "returned value is not valid SD\n");
755 ret
= GetSecurityDescriptorControl(psd
, &control
, &dwRev
);
756 ok(ret
, "GetSecurityDescriptorControl failed with error %u\n", GetLastError());
757 ok(0 == (control
& SE_SELF_RELATIVE
), "SD should be absolute\n");
759 ret
= GetSecurityDescriptorDacl(psd
, &bHasDacl
, &pAcl
, &bDefaulted
);
760 ok(ret
, "GetSecurityDescriptorDacl failed with error %u\n", GetLastError());
762 ok(bHasDacl
, "SD has no DACL\n");
765 ok(!bDefaulted
, "DACL should not be defaulted\n");
767 ok(pAcl
!= NULL
, "NULL DACL!\n");
770 ACL_SIZE_INFORMATION asiSize
;
772 ok(IsValidAcl(pAcl
), "DACL is not valid\n");
774 ret
= GetAclInformation(pAcl
, &asiSize
, sizeof(asiSize
), AclSizeInformation
);
775 ok(ret
, "GetAclInformation failed with error %u\n", GetLastError());
777 ok(asiSize
.AceCount
== 3, "Incorrect number of ACEs: %d entries\n", asiSize
.AceCount
);
778 if (asiSize
.AceCount
== 3)
780 ACCESS_ALLOWED_ACE
*paaa
; /* will use for DENIED too */
782 ret
= GetAce(pAcl
, 0, (LPVOID
*)&paaa
);
783 ok(ret
, "GetAce failed with error %u\n", GetLastError());
784 ok(paaa
->Header
.AceType
== ACCESS_ALLOWED_ACE_TYPE
,
785 "Invalid ACE type %d\n", paaa
->Header
.AceType
);
786 ok(paaa
->Header
.AceFlags
== 0, "Invalid ACE flags %x\n", paaa
->Header
.AceFlags
);
787 ok(paaa
->Mask
== GENERIC_ALL
, "Invalid ACE mask %x\n", paaa
->Mask
);
789 ret
= GetAce(pAcl
, 1, (LPVOID
*)&paaa
);
790 ok(ret
, "GetAce failed with error %u\n", GetLastError());
791 ok(paaa
->Header
.AceType
== ACCESS_DENIED_ACE_TYPE
,
792 "Invalid ACE type %d\n", paaa
->Header
.AceType
);
793 /* first one of two ACEs generated from inheritable entry - without inheritance */
794 ok(paaa
->Header
.AceFlags
== 0, "Invalid ACE flags %x\n", paaa
->Header
.AceFlags
);
795 ok(paaa
->Mask
== GENERIC_WRITE
, "Invalid ACE mask %x\n", paaa
->Mask
);
797 ret
= GetAce(pAcl
, 2, (LPVOID
*)&paaa
);
798 ok(ret
, "GetAce failed with error %u\n", GetLastError());
799 ok(paaa
->Header
.AceType
== ACCESS_DENIED_ACE_TYPE
,
800 "Invalid ACE type %d\n", paaa
->Header
.AceType
);
801 /* second ACE - with inheritance */
802 ok(paaa
->Header
.AceFlags
== MY_INHERITANCE
,
803 "Invalid ACE flags %x\n", paaa
->Header
.AceFlags
);
804 ok(paaa
->Mask
== GENERIC_READ
, "Invalid ACE mask %x\n", paaa
->Mask
);
813 static void test_SHPackDispParams(void)
819 if(!pSHPackDispParams
)
820 win_skip("SHPackSidpParams not available\n");
822 memset(¶ms
, 0xc0, sizeof(params
));
823 memset(vars
, 0xc0, sizeof(vars
));
824 hres
= pSHPackDispParams(¶ms
, vars
, 1, VT_I4
, 0xdeadbeef);
825 ok(hres
== S_OK
, "SHPackDispParams failed: %08x\n", hres
);
826 ok(params
.cArgs
== 1, "params.cArgs = %d\n", params
.cArgs
);
827 ok(params
.cNamedArgs
== 0, "params.cNamedArgs = %d\n", params
.cArgs
);
828 ok(params
.rgdispidNamedArgs
== NULL
, "params.rgdispidNamedArgs = %p\n", params
.rgdispidNamedArgs
);
829 ok(params
.rgvarg
== vars
, "params.rgvarg = %p\n", params
.rgvarg
);
830 ok(V_VT(vars
) == VT_I4
, "V_VT(var) = %d\n", V_VT(vars
));
831 ok(V_I4(vars
) == 0xdeadbeef, "failed %x\n", V_I4(vars
));
833 memset(¶ms
, 0xc0, sizeof(params
));
834 hres
= pSHPackDispParams(¶ms
, NULL
, 0, 0);
835 ok(hres
== S_OK
, "SHPackDispParams failed: %08x\n", hres
);
836 ok(params
.cArgs
== 0, "params.cArgs = %d\n", params
.cArgs
);
837 ok(params
.cNamedArgs
== 0, "params.cNamedArgs = %d\n", params
.cArgs
);
838 ok(params
.rgdispidNamedArgs
== NULL
, "params.rgdispidNamedArgs = %p\n", params
.rgdispidNamedArgs
);
839 ok(params
.rgvarg
== NULL
, "params.rgvarg = %p\n", params
.rgvarg
);
841 memset(vars
, 0xc0, sizeof(vars
));
842 memset(¶ms
, 0xc0, sizeof(params
));
843 hres
= pSHPackDispParams(¶ms
, vars
, 4, VT_BSTR
, (void*)0xdeadbeef, VT_EMPTY
, 10,
844 VT_I4
, 100, VT_DISPATCH
, (void*)0xdeadbeef);
845 ok(hres
== S_OK
, "SHPackDispParams failed: %08x\n", hres
);
846 ok(params
.cArgs
== 4, "params.cArgs = %d\n", params
.cArgs
);
847 ok(params
.cNamedArgs
== 0, "params.cNamedArgs = %d\n", params
.cArgs
);
848 ok(params
.rgdispidNamedArgs
== NULL
, "params.rgdispidNamedArgs = %p\n", params
.rgdispidNamedArgs
);
849 ok(params
.rgvarg
== vars
, "params.rgvarg = %p\n", params
.rgvarg
);
850 ok(V_VT(vars
) == VT_DISPATCH
, "V_VT(vars[0]) = %x\n", V_VT(vars
));
851 ok(V_I4(vars
) == 0xdeadbeef, "V_I4(vars[0]) = %x\n", V_I4(vars
));
852 ok(V_VT(vars
+1) == VT_I4
, "V_VT(vars[1]) = %d\n", V_VT(vars
+1));
853 ok(V_I4(vars
+1) == 100, "V_I4(vars[1]) = %x\n", V_I4(vars
+1));
854 ok(V_VT(vars
+2) == VT_I4
, "V_VT(vars[2]) = %d\n", V_VT(vars
+2));
855 ok(V_I4(vars
+2) == 10, "V_I4(vars[2]) = %x\n", V_I4(vars
+2));
856 ok(V_VT(vars
+3) == VT_BSTR
, "V_VT(vars[3]) = %d\n", V_VT(vars
+3));
857 ok(V_BSTR(vars
+3) == (void*)0xdeadbeef, "V_BSTR(vars[3]) = %p\n", V_BSTR(vars
+3));
862 IDispatch IDispatch_iface
;
866 static inline Disp
*impl_from_IDispatch(IDispatch
*iface
)
868 return CONTAINING_RECORD(iface
, Disp
, IDispatch_iface
);
871 typedef struct _contain
873 IConnectionPointContainer IConnectionPointContainer_iface
;
877 IConnectionPoint
**pt
;
880 static inline Contain
*impl_from_IConnectionPointContainer(IConnectionPointContainer
*iface
)
882 return CONTAINING_RECORD(iface
, Contain
, IConnectionPointContainer_iface
);
885 typedef struct _cntptn
887 IConnectionPoint IConnectionPoint_iface
;
896 static inline ConPt
*impl_from_IConnectionPoint(IConnectionPoint
*iface
)
898 return CONTAINING_RECORD(iface
, ConPt
, IConnectionPoint_iface
);
903 IEnumConnections IEnumConnections_iface
;
910 static inline EnumCon
*impl_from_IEnumConnections(IEnumConnections
*iface
)
912 return CONTAINING_RECORD(iface
, EnumCon
, IEnumConnections_iface
);
915 typedef struct _enumpt
917 IEnumConnectionPoints IEnumConnectionPoints_iface
;
924 static inline EnumPt
*impl_from_IEnumConnectionPoints(IEnumConnectionPoints
*iface
)
926 return CONTAINING_RECORD(iface
, EnumPt
, IEnumConnectionPoints_iface
);
930 static HRESULT WINAPI
Disp_QueryInterface(
937 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IDispatch
))
944 IDispatch_AddRef(This
);
948 trace("no interface\n");
949 return E_NOINTERFACE
;
952 static ULONG WINAPI
Disp_AddRef(IDispatch
* This
)
954 Disp
*iface
= impl_from_IDispatch(This
);
955 return InterlockedIncrement(&iface
->refCount
);
958 static ULONG WINAPI
Disp_Release(IDispatch
* This
)
960 Disp
*iface
= impl_from_IDispatch(This
);
963 ret
= InterlockedDecrement(&iface
->refCount
);
965 HeapFree(GetProcessHeap(),0,This
);
969 static HRESULT WINAPI
Disp_GetTypeInfoCount(
973 return ERROR_SUCCESS
;
976 static HRESULT WINAPI
Disp_GetTypeInfo(
982 return ERROR_SUCCESS
;
985 static HRESULT WINAPI
Disp_GetIDsOfNames(
993 return ERROR_SUCCESS
;
996 static HRESULT WINAPI
Disp_Invoke(
1002 DISPPARAMS
*pDispParams
,
1003 VARIANT
*pVarResult
,
1004 EXCEPINFO
*pExcepInfo
,
1007 trace("%p %x %p %x %x %p %p %p %p\n",This
,dispIdMember
,riid
,lcid
,wFlags
,pDispParams
,pVarResult
,pExcepInfo
,puArgErr
);
1009 ok(dispIdMember
== 0xa0 || dispIdMember
== 0xa1, "Unknown dispIdMember\n");
1010 ok(pDispParams
!= NULL
, "Invoked with NULL pDispParams\n");
1011 ok(wFlags
== DISPATCH_METHOD
, "Wrong flags %x\n",wFlags
);
1012 ok(lcid
== 0,"Wrong lcid %x\n",lcid
);
1013 if (dispIdMember
== 0xa0)
1015 ok(pDispParams
->cArgs
== 0, "params.cArgs = %d\n", pDispParams
->cArgs
);
1016 ok(pDispParams
->cNamedArgs
== 0, "params.cNamedArgs = %d\n", pDispParams
->cArgs
);
1017 ok(pDispParams
->rgdispidNamedArgs
== NULL
, "params.rgdispidNamedArgs = %p\n", pDispParams
->rgdispidNamedArgs
);
1018 ok(pDispParams
->rgvarg
== NULL
, "params.rgvarg = %p\n", pDispParams
->rgvarg
);
1020 else if (dispIdMember
== 0xa1)
1022 ok(pDispParams
->cArgs
== 2, "params.cArgs = %d\n", pDispParams
->cArgs
);
1023 ok(pDispParams
->cNamedArgs
== 0, "params.cNamedArgs = %d\n", pDispParams
->cArgs
);
1024 ok(pDispParams
->rgdispidNamedArgs
== NULL
, "params.rgdispidNamedArgs = %p\n", pDispParams
->rgdispidNamedArgs
);
1025 ok(V_VT(pDispParams
->rgvarg
) == VT_BSTR
, "V_VT(var) = %d\n", V_VT(pDispParams
->rgvarg
));
1026 ok(V_I4(pDispParams
->rgvarg
) == 0xdeadcafe , "failed %p\n", V_BSTR(pDispParams
->rgvarg
));
1027 ok(V_VT(pDispParams
->rgvarg
+1) == VT_I4
, "V_VT(var) = %d\n", V_VT(pDispParams
->rgvarg
+1));
1028 ok(V_I4(pDispParams
->rgvarg
+1) == 0xdeadbeef, "failed %x\n", V_I4(pDispParams
->rgvarg
+1));
1031 return ERROR_SUCCESS
;
1034 static const IDispatchVtbl disp_vtbl
= {
1035 Disp_QueryInterface
,
1039 Disp_GetTypeInfoCount
,
1045 static HRESULT WINAPI
Enum_QueryInterface(
1046 IEnumConnections
* This
,
1052 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IEnumConnections
))
1059 IEnumConnections_AddRef(This
);
1063 trace("no interface\n");
1064 return E_NOINTERFACE
;
1067 static ULONG WINAPI
Enum_AddRef(IEnumConnections
* This
)
1069 EnumCon
*iface
= impl_from_IEnumConnections(This
);
1070 return InterlockedIncrement(&iface
->refCount
);
1073 static ULONG WINAPI
Enum_Release(IEnumConnections
* This
)
1075 EnumCon
*iface
= impl_from_IEnumConnections(This
);
1078 ret
= InterlockedDecrement(&iface
->refCount
);
1080 HeapFree(GetProcessHeap(),0,This
);
1084 static HRESULT WINAPI
Enum_Next(
1085 IEnumConnections
* This
,
1090 EnumCon
*iface
= impl_from_IEnumConnections(This
);
1092 if (cConnections
> 0 && iface
->idx
< iface
->pt
->sinkCount
)
1094 rgcd
->pUnk
= iface
->pt
->sink
[iface
->idx
];
1095 IUnknown_AddRef(iface
->pt
->sink
[iface
->idx
]);
1096 rgcd
->dwCookie
=0xff;
1106 static HRESULT WINAPI
Enum_Skip(
1107 IEnumConnections
* This
,
1113 static HRESULT WINAPI
Enum_Reset(
1114 IEnumConnections
* This
)
1119 static HRESULT WINAPI
Enum_Clone(
1120 IEnumConnections
* This
,
1121 IEnumConnections
**ppEnum
)
1126 static const IEnumConnectionsVtbl enum_vtbl
= {
1128 Enum_QueryInterface
,
1137 static HRESULT WINAPI
ConPt_QueryInterface(
1138 IConnectionPoint
* This
,
1144 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IConnectionPoint
))
1151 IConnectionPoint_AddRef(This
);
1155 trace("no interface\n");
1156 return E_NOINTERFACE
;
1159 static ULONG WINAPI
ConPt_AddRef(
1160 IConnectionPoint
* This
)
1162 ConPt
*iface
= impl_from_IConnectionPoint(This
);
1163 return InterlockedIncrement(&iface
->refCount
);
1166 static ULONG WINAPI
ConPt_Release(
1167 IConnectionPoint
* This
)
1169 ConPt
*iface
= impl_from_IConnectionPoint(This
);
1172 ret
= InterlockedDecrement(&iface
->refCount
);
1175 if (iface
->sinkCount
> 0)
1178 for (i
= 0; i
< iface
->sinkCount
; i
++)
1181 IUnknown_Release(iface
->sink
[i
]);
1183 HeapFree(GetProcessHeap(),0,iface
->sink
);
1185 HeapFree(GetProcessHeap(),0,This
);
1190 static HRESULT WINAPI
ConPt_GetConnectionInterface(
1191 IConnectionPoint
* This
,
1195 ConPt
*iface
= impl_from_IConnectionPoint(This
);
1202 memcpy(pIID
,&iface
->id
,sizeof(GUID
));
1206 static HRESULT WINAPI
ConPt_GetConnectionPointContainer(
1207 IConnectionPoint
* This
,
1208 IConnectionPointContainer
**ppCPC
)
1210 ConPt
*iface
= impl_from_IConnectionPoint(This
);
1212 *ppCPC
= &iface
->container
->IConnectionPointContainer_iface
;
1216 static HRESULT WINAPI
ConPt_Advise(
1217 IConnectionPoint
* This
,
1221 ConPt
*iface
= impl_from_IConnectionPoint(This
);
1223 if (iface
->sinkCount
== 0)
1224 iface
->sink
= HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown
*));
1226 iface
->sink
= HeapReAlloc(GetProcessHeap(),0,iface
->sink
,sizeof(IUnknown
*)*(iface
->sinkCount
+1));
1227 iface
->sink
[iface
->sinkCount
] = pUnkSink
;
1228 IUnknown_AddRef(pUnkSink
);
1230 *pdwCookie
= iface
->sinkCount
;
1234 static HRESULT WINAPI
ConPt_Unadvise(
1235 IConnectionPoint
* This
,
1238 ConPt
*iface
= impl_from_IConnectionPoint(This
);
1240 if (dwCookie
> iface
->sinkCount
)
1244 IUnknown_Release(iface
->sink
[dwCookie
-1]);
1245 iface
->sink
[dwCookie
-1] = NULL
;
1250 static HRESULT WINAPI
ConPt_EnumConnections(
1251 IConnectionPoint
* This
,
1252 IEnumConnections
**ppEnum
)
1256 ec
= HeapAlloc(GetProcessHeap(),0,sizeof(EnumCon
));
1257 ec
->IEnumConnections_iface
.lpVtbl
= &enum_vtbl
;
1259 ec
->pt
= impl_from_IConnectionPoint(This
);
1261 *ppEnum
= &ec
->IEnumConnections_iface
;
1266 static const IConnectionPointVtbl point_vtbl
= {
1267 ConPt_QueryInterface
,
1271 ConPt_GetConnectionInterface
,
1272 ConPt_GetConnectionPointContainer
,
1275 ConPt_EnumConnections
1278 static HRESULT WINAPI
EnumPt_QueryInterface(
1279 IEnumConnectionPoints
* This
,
1285 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IEnumConnectionPoints
))
1292 IEnumConnectionPoints_AddRef(This
);
1296 trace("no interface\n");
1297 return E_NOINTERFACE
;
1300 static ULONG WINAPI
EnumPt_AddRef(IEnumConnectionPoints
* This
)
1302 EnumPt
*iface
= impl_from_IEnumConnectionPoints(This
);
1303 return InterlockedIncrement(&iface
->refCount
);
1306 static ULONG WINAPI
EnumPt_Release(IEnumConnectionPoints
* This
)
1308 EnumPt
*iface
= impl_from_IEnumConnectionPoints(This
);
1311 ret
= InterlockedDecrement(&iface
->refCount
);
1313 HeapFree(GetProcessHeap(),0,This
);
1317 static HRESULT WINAPI
EnumPt_Next(
1318 IEnumConnectionPoints
* This
,
1320 IConnectionPoint
**rgcd
,
1323 EnumPt
*iface
= impl_from_IEnumConnectionPoints(This
);
1325 if (cConnections
> 0 && iface
->idx
< iface
->container
->ptCount
)
1327 *rgcd
= iface
->container
->pt
[iface
->idx
];
1328 IConnectionPoint_AddRef(iface
->container
->pt
[iface
->idx
]);
1338 static HRESULT WINAPI
EnumPt_Skip(
1339 IEnumConnectionPoints
* This
,
1345 static HRESULT WINAPI
EnumPt_Reset(
1346 IEnumConnectionPoints
* This
)
1351 static HRESULT WINAPI
EnumPt_Clone(
1352 IEnumConnectionPoints
* This
,
1353 IEnumConnectionPoints
**ppEnumPt
)
1358 static const IEnumConnectionPointsVtbl enumpt_vtbl
= {
1360 EnumPt_QueryInterface
,
1369 static HRESULT WINAPI
Contain_QueryInterface(
1370 IConnectionPointContainer
* This
,
1376 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IConnectionPointContainer
))
1383 IConnectionPointContainer_AddRef(This
);
1387 trace("no interface\n");
1388 return E_NOINTERFACE
;
1391 static ULONG WINAPI
Contain_AddRef(
1392 IConnectionPointContainer
* This
)
1394 Contain
*iface
= impl_from_IConnectionPointContainer(This
);
1395 return InterlockedIncrement(&iface
->refCount
);
1398 static ULONG WINAPI
Contain_Release(
1399 IConnectionPointContainer
* This
)
1401 Contain
*iface
= impl_from_IConnectionPointContainer(This
);
1404 ret
= InterlockedDecrement(&iface
->refCount
);
1407 if (iface
->ptCount
> 0)
1410 for (i
= 0; i
< iface
->ptCount
; i
++)
1411 IConnectionPoint_Release(iface
->pt
[i
]);
1412 HeapFree(GetProcessHeap(),0,iface
->pt
);
1414 HeapFree(GetProcessHeap(),0,This
);
1419 static HRESULT WINAPI
Contain_EnumConnectionPoints(
1420 IConnectionPointContainer
* This
,
1421 IEnumConnectionPoints
**ppEnum
)
1425 ec
= HeapAlloc(GetProcessHeap(),0,sizeof(EnumPt
));
1426 ec
->IEnumConnectionPoints_iface
.lpVtbl
= &enumpt_vtbl
;
1429 ec
->container
= impl_from_IConnectionPointContainer(This
);
1430 *ppEnum
= &ec
->IEnumConnectionPoints_iface
;
1435 static HRESULT WINAPI
Contain_FindConnectionPoint(
1436 IConnectionPointContainer
* This
,
1438 IConnectionPoint
**ppCP
)
1440 Contain
*iface
= impl_from_IConnectionPointContainer(This
);
1443 if (!IsEqualIID(riid
, &IID_NULL
) || iface
->ptCount
==0)
1445 pt
= HeapAlloc(GetProcessHeap(),0,sizeof(ConPt
));
1446 pt
->IConnectionPoint_iface
.lpVtbl
= &point_vtbl
;
1450 pt
->container
= iface
;
1451 pt
->id
= IID_IDispatch
;
1453 if (iface
->ptCount
== 0)
1454 iface
->pt
=HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown
*));
1456 iface
->pt
= HeapReAlloc(GetProcessHeap(),0,iface
->pt
,sizeof(IUnknown
*)*(iface
->ptCount
+1));
1457 iface
->pt
[iface
->ptCount
] = &pt
->IConnectionPoint_iface
;
1460 *ppCP
= &pt
->IConnectionPoint_iface
;
1464 *ppCP
= iface
->pt
[0];
1465 IUnknown_AddRef((IUnknown
*)*ppCP
);
1471 static const IConnectionPointContainerVtbl contain_vtbl
= {
1472 Contain_QueryInterface
,
1476 Contain_EnumConnectionPoints
,
1477 Contain_FindConnectionPoint
1480 static void test_IConnectionPoint(void)
1484 IConnectionPoint
*point
;
1487 DWORD cookie
= 0xffffffff;
1491 if (!pIConnectionPoint_SimpleInvoke
|| !pConnectToConnectionPoint
)
1493 win_skip("IConnectionPoint Apis not present\n");
1497 container
= HeapAlloc(GetProcessHeap(),0,sizeof(Contain
));
1498 container
->IConnectionPointContainer_iface
.lpVtbl
= &contain_vtbl
;
1499 container
->refCount
= 1;
1500 container
->ptCount
= 0;
1501 container
->pt
= NULL
;
1503 dispatch
= HeapAlloc(GetProcessHeap(),0,sizeof(Disp
));
1504 dispatch
->IDispatch_iface
.lpVtbl
= &disp_vtbl
;
1505 dispatch
->refCount
= 1;
1507 rc
= pConnectToConnectionPoint((IUnknown
*)dispatch
, &IID_NULL
, TRUE
, (IUnknown
*)container
, &cookie
, &point
);
1508 ok(rc
== S_OK
, "pConnectToConnectionPoint failed with %x\n",rc
);
1509 ok(point
!= NULL
, "returned ConnectionPoint is NULL\n");
1510 ok(cookie
!= 0xffffffff, "invalid cookie returned\n");
1512 rc
= pIConnectionPoint_SimpleInvoke(point
,0xa0,NULL
);
1513 ok(rc
== S_OK
, "pConnectToConnectionPoint failed with %x\n",rc
);
1515 if (pSHPackDispParams
)
1517 memset(¶ms
, 0xc0, sizeof(params
));
1518 memset(vars
, 0xc0, sizeof(vars
));
1519 rc
= pSHPackDispParams(¶ms
, vars
, 2, VT_I4
, 0xdeadbeef, VT_BSTR
, 0xdeadcafe);
1520 ok(rc
== S_OK
, "SHPackDispParams failed: %08x\n", rc
);
1522 rc
= pIConnectionPoint_SimpleInvoke(point
,0xa1,¶ms
);
1523 ok(rc
== S_OK
, "pConnectToConnectionPoint failed with %x\n",rc
);
1526 win_skip("pSHPackDispParams not present\n");
1528 rc
= pConnectToConnectionPoint(NULL
, &IID_NULL
, FALSE
, (IUnknown
*)container
, &cookie
, NULL
);
1529 ok(rc
== S_OK
, "pConnectToConnectionPoint failed with %x\n",rc
);
1531 /* MSDN says this should be required but it crashs on XP
1532 IUnknown_Release(point);
1534 ref
= IUnknown_Release((IUnknown
*)container
);
1535 ok(ref
== 0, "leftover IConnectionPointContainer reference %i\n",ref
);
1536 ref
= IUnknown_Release((IUnknown
*)dispatch
);
1537 ok(ref
== 0, "leftover IDispatch reference %i\n",ref
);
1540 typedef struct _propbag
1542 IPropertyBag IPropertyBag_iface
;
1547 static inline PropBag
*impl_from_IPropertyBag(IPropertyBag
*iface
)
1549 return CONTAINING_RECORD(iface
, PropBag
, IPropertyBag_iface
);
1553 static HRESULT WINAPI
Prop_QueryInterface(
1560 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IPropertyBag
))
1567 IPropertyBag_AddRef(This
);
1571 trace("no interface\n");
1572 return E_NOINTERFACE
;
1575 static ULONG WINAPI
Prop_AddRef(
1578 PropBag
*iface
= impl_from_IPropertyBag(This
);
1579 return InterlockedIncrement(&iface
->refCount
);
1582 static ULONG WINAPI
Prop_Release(
1585 PropBag
*iface
= impl_from_IPropertyBag(This
);
1588 ret
= InterlockedDecrement(&iface
->refCount
);
1590 HeapFree(GetProcessHeap(),0,This
);
1594 static HRESULT WINAPI
Prop_Read(
1596 LPCOLESTR pszPropName
,
1598 IErrorLog
*pErrorLog
)
1600 V_VT(pVar
) = VT_BLOB
|VT_BYREF
;
1601 V_BYREF(pVar
) = (LPVOID
)0xdeadcafe;
1605 static HRESULT WINAPI
Prop_Write(
1607 LPCOLESTR pszPropName
,
1614 static const IPropertyBagVtbl prop_vtbl
= {
1615 Prop_QueryInterface
,
1623 static void test_SHPropertyBag_ReadLONG(void)
1628 static const WCHAR szName1
[] = {'n','a','m','e','1',0};
1630 if (!pSHPropertyBag_ReadLONG
)
1632 win_skip("SHPropertyBag_ReadLONG not present\n");
1636 pb
= HeapAlloc(GetProcessHeap(),0,sizeof(PropBag
));
1638 pb
->IPropertyBag_iface
.lpVtbl
= &prop_vtbl
;
1641 rc
= pSHPropertyBag_ReadLONG(NULL
, szName1
, &out
);
1642 ok(rc
== E_INVALIDARG
|| broken(rc
== S_OK
), "incorrect return %x\n",rc
);
1643 ok(out
== 0xfeedface, "value should not have changed\n");
1644 rc
= pSHPropertyBag_ReadLONG(&pb
->IPropertyBag_iface
, NULL
, &out
);
1645 ok(rc
== E_INVALIDARG
|| broken(rc
== S_OK
) || broken(rc
== S_FALSE
), "incorrect return %x\n",rc
);
1646 ok(out
== 0xfeedface, "value should not have changed\n");
1647 rc
= pSHPropertyBag_ReadLONG(&pb
->IPropertyBag_iface
, szName1
, NULL
);
1648 ok(rc
== E_INVALIDARG
|| broken(rc
== S_OK
) || broken(rc
== S_FALSE
), "incorrect return %x\n",rc
);
1649 rc
= pSHPropertyBag_ReadLONG(&pb
->IPropertyBag_iface
, szName1
, &out
);
1650 ok(rc
== DISP_E_BADVARTYPE
|| broken(rc
== S_OK
) || broken(rc
== S_FALSE
), "incorrect return %x\n",rc
);
1651 ok(out
== 0xfeedface || broken(out
== 0xfeedfa00), "value should not have changed %x\n",out
);
1652 IUnknown_Release((IUnknown
*)pb
);
1655 static void test_SHSetWindowBits(void)
1658 DWORD style
, styleold
;
1661 if(!pSHSetWindowBits
)
1663 win_skip("SHSetWindowBits is not available\n");
1668 clsA
.lpfnWndProc
= DefWindowProcA
;
1669 clsA
.cbClsExtra
= 0;
1670 clsA
.cbWndExtra
= 0;
1671 clsA
.hInstance
= GetModuleHandleA(NULL
);
1673 clsA
.hCursor
= LoadCursorA(0, (LPSTR
)IDC_ARROW
);
1674 clsA
.hbrBackground
= NULL
;
1675 clsA
.lpszMenuName
= NULL
;
1676 clsA
.lpszClassName
= "Shlwapi test class";
1677 RegisterClassA(&clsA
);
1679 hwnd
= CreateWindowA("Shlwapi test class", "Test", WS_VISIBLE
, 0, 0, 100, 100,
1680 NULL
, NULL
, GetModuleHandleA(NULL
), 0);
1681 ok(IsWindow(hwnd
), "failed to create window\n");
1684 SetLastError(0xdeadbeef);
1685 style
= pSHSetWindowBits(NULL
, GWL_STYLE
, 0, 0);
1686 ok(style
== 0, "expected 0 retval, got %d\n", style
);
1687 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE
||
1688 broken(GetLastError() == 0xdeadbeef), /* Win9x/WinMe */
1689 "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
1691 /* zero mask, zero flags */
1692 styleold
= GetWindowLongA(hwnd
, GWL_STYLE
);
1693 style
= pSHSetWindowBits(hwnd
, GWL_STYLE
, 0, 0);
1694 ok(styleold
== style
, "expected old style\n");
1695 ok(styleold
== GetWindowLongA(hwnd
, GWL_STYLE
), "expected to keep old style\n");
1698 styleold
= GetWindowLongA(hwnd
, GWL_STYLE
);
1699 ok(styleold
& WS_VISIBLE
, "expected WS_VISIBLE\n");
1700 style
= pSHSetWindowBits(hwnd
, GWL_STYLE
, WS_VISIBLE
, 0);
1702 ok(style
== styleold
, "expected previous style, got %x\n", style
);
1703 ok((GetWindowLongA(hwnd
, GWL_STYLE
) & WS_VISIBLE
) == 0, "expected updated style\n");
1705 /* test mask, unset style bit used */
1706 styleold
= GetWindowLongA(hwnd
, GWL_STYLE
);
1707 style
= pSHSetWindowBits(hwnd
, GWL_STYLE
, WS_VISIBLE
, 0);
1708 ok(style
== styleold
, "expected previous style, got %x\n", style
);
1709 ok(styleold
== GetWindowLongA(hwnd
, GWL_STYLE
), "expected to keep old style\n");
1711 /* set back with flags */
1712 styleold
= GetWindowLongA(hwnd
, GWL_STYLE
);
1713 style
= pSHSetWindowBits(hwnd
, GWL_STYLE
, WS_VISIBLE
, WS_VISIBLE
);
1714 ok(style
== styleold
, "expected previous style, got %x\n", style
);
1715 ok(GetWindowLongA(hwnd
, GWL_STYLE
) & WS_VISIBLE
, "expected updated style\n");
1717 /* reset and try to set without a mask */
1718 pSHSetWindowBits(hwnd
, GWL_STYLE
, WS_VISIBLE
, 0);
1719 ok((GetWindowLongA(hwnd
, GWL_STYLE
) & WS_VISIBLE
) == 0, "expected updated style\n");
1720 styleold
= GetWindowLongA(hwnd
, GWL_STYLE
);
1721 style
= pSHSetWindowBits(hwnd
, GWL_STYLE
, 0, WS_VISIBLE
);
1722 ok(style
== styleold
, "expected previous style, got %x\n", style
);
1723 ok((GetWindowLongA(hwnd
, GWL_STYLE
) & WS_VISIBLE
) == 0, "expected updated style\n");
1725 DestroyWindow(hwnd
);
1727 UnregisterClassA("Shlwapi test class", GetModuleHandleA(NULL
));
1730 static void test_SHFormatDateTimeA(void)
1732 FILETIME UNALIGNED filetime
;
1733 CHAR buff
[100], buff2
[100], buff3
[100];
1738 if(!pSHFormatDateTimeA
)
1740 win_skip("pSHFormatDateTimeA isn't available\n");
1746 /* crashes on native */
1747 pSHFormatDateTimeA(NULL
, NULL
, NULL
, 0);
1751 SystemTimeToFileTime(&st
, &filetime
);
1752 /* SHFormatDateTime expects input as utc */
1753 LocalFileTimeToFileTime(&filetime
, &filetime
);
1755 /* no way to get required buffer length here */
1756 SetLastError(0xdeadbeef);
1757 ret
= pSHFormatDateTimeA(&filetime
, NULL
, NULL
, 0);
1758 ok(ret
== 0, "got %d\n", ret
);
1759 ok(GetLastError() == 0xdeadbeef || broken(GetLastError() == ERROR_SUCCESS
/* Win7 */),
1760 "expected 0xdeadbeef, got %d\n", GetLastError());
1762 SetLastError(0xdeadbeef);
1763 buff
[0] = 'a'; buff
[1] = 0;
1764 ret
= pSHFormatDateTimeA(&filetime
, NULL
, buff
, 0);
1765 ok(ret
== 0, "got %d\n", ret
);
1766 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1767 ok(buff
[0] == 'a', "expected same string, got %s\n", buff
);
1769 /* flags needs to have FDTF_NOAUTOREADINGORDER for these tests to succeed on Vista+ */
1771 /* all combinations documented as invalid succeeded */
1772 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_SHORTTIME
| FDTF_LONGTIME
;
1773 SetLastError(0xdeadbeef);
1774 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1775 ok(ret
== lstrlenA(buff
)+1, "got %d\n", ret
);
1776 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1778 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_SHORTDATE
| FDTF_LONGDATE
;
1779 SetLastError(0xdeadbeef);
1780 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1781 ok(ret
== lstrlenA(buff
)+1, "got %d\n", ret
);
1782 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1784 flags
= FDTF_SHORTDATE
| FDTF_LTRDATE
| FDTF_RTLDATE
;
1785 SetLastError(0xdeadbeef);
1786 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1787 ok(ret
== lstrlenA(buff
)+1, "got %d\n", ret
);
1788 ok(GetLastError() == 0xdeadbeef ||
1789 broken(GetLastError() == ERROR_INVALID_FLAGS
), /* Win9x/WinMe */
1790 "expected 0xdeadbeef, got %d\n", GetLastError());
1792 /* now check returned strings */
1793 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_SHORTTIME
;
1794 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1795 ok(ret
== lstrlenA(buff
)+1, "got %d\n", ret
);
1796 ret
= GetTimeFormatA(LOCALE_USER_DEFAULT
, TIME_NOSECONDS
, &st
, NULL
, buff2
, sizeof(buff2
));
1797 ok(ret
== lstrlenA(buff2
)+1, "got %d\n", ret
);
1798 ok(lstrcmpA(buff
, buff2
) == 0, "expected (%s), got (%s)\n", buff2
, buff
);
1800 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_LONGTIME
;
1801 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1802 ok(ret
== lstrlenA(buff
)+1, "got %d\n", ret
);
1803 ret
= GetTimeFormatA(LOCALE_USER_DEFAULT
, 0, &st
, NULL
, buff2
, sizeof(buff2
));
1804 ok(ret
== lstrlenA(buff2
)+1, "got %d\n", ret
);
1805 ok(lstrcmpA(buff
, buff2
) == 0, "expected (%s), got (%s)\n", buff2
, buff
);
1807 /* both time flags */
1808 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_LONGTIME
| FDTF_SHORTTIME
;
1809 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1810 ok(ret
== lstrlenA(buff
)+1, "got %d\n", ret
);
1811 ret
= GetTimeFormatA(LOCALE_USER_DEFAULT
, 0, &st
, NULL
, buff2
, sizeof(buff2
));
1812 ok(ret
== lstrlenA(buff2
)+1, "got %d\n", ret
);
1813 ok(lstrcmpA(buff
, buff2
) == 0, "expected (%s), got (%s)\n", buff2
, buff
);
1815 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_SHORTDATE
;
1816 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1817 ok(ret
== lstrlenA(buff
)+1, "got %d\n", ret
);
1818 ret
= GetDateFormatA(LOCALE_USER_DEFAULT
, DATE_SHORTDATE
, &st
, NULL
, buff2
, sizeof(buff2
));
1819 ok(ret
== lstrlenA(buff2
)+1, "got %d\n", ret
);
1820 ok(lstrcmpA(buff
, buff2
) == 0, "expected (%s), got (%s)\n", buff2
, buff
);
1822 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_LONGDATE
;
1823 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1824 ok(ret
== lstrlenA(buff
)+1, "got %d\n", ret
);
1825 ret
= GetDateFormatA(LOCALE_USER_DEFAULT
, DATE_LONGDATE
, &st
, NULL
, buff2
, sizeof(buff2
));
1826 ok(ret
== lstrlenA(buff2
)+1, "got %d\n", ret
);
1827 ok(lstrcmpA(buff
, buff2
) == 0, "expected (%s), got (%s)\n", buff2
, buff
);
1829 /* both date flags */
1830 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_LONGDATE
| FDTF_SHORTDATE
;
1831 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1832 ok(ret
== lstrlenA(buff
)+1, "got %d\n", ret
);
1833 ret
= GetDateFormatA(LOCALE_USER_DEFAULT
, DATE_LONGDATE
, &st
, NULL
, buff2
, sizeof(buff2
));
1834 ok(ret
== lstrlenA(buff2
)+1, "got %d\n", ret
);
1835 ok(lstrcmpA(buff
, buff2
) == 0, "expected (%s), got (%s)\n", buff2
, buff
);
1837 /* various combinations of date/time flags */
1838 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_LONGDATE
| FDTF_SHORTTIME
;
1839 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1840 ok(ret
== lstrlenA(buff
)+1, "got %d, length %d\n", ret
, lstrlenA(buff
)+1);
1841 ret
= GetTimeFormatA(LOCALE_USER_DEFAULT
, TIME_NOSECONDS
, &st
, NULL
, buff3
, sizeof(buff3
));
1842 ok(ret
== lstrlenA(buff3
)+1, "got %d\n", ret
);
1843 ok(lstrcmpA(buff3
, buff
+ lstrlenA(buff
) - lstrlenA(buff3
)) == 0,
1844 "expected (%s), got (%s) for time part\n",
1845 buff3
, buff
+ lstrlenA(buff
) - lstrlenA(buff3
));
1846 ret
= GetDateFormatA(LOCALE_USER_DEFAULT
, DATE_LONGDATE
, &st
, NULL
, buff2
, sizeof(buff2
));
1847 ok(ret
== lstrlenA(buff2
)+1, "got %d\n", ret
);
1848 buff
[lstrlenA(buff2
)] = '\0';
1849 ok(lstrcmpA(buff2
, buff
) == 0, "expected (%s) got (%s) for date part\n",
1852 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_LONGDATE
| FDTF_LONGTIME
;
1853 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1854 ok(ret
== lstrlenA(buff
)+1, "got %d\n", ret
);
1855 ret
= GetTimeFormatA(LOCALE_USER_DEFAULT
, 0, &st
, NULL
, buff3
, sizeof(buff3
));
1856 ok(ret
== lstrlenA(buff3
)+1, "got %d\n", ret
);
1857 ok(lstrcmpA(buff3
, buff
+ lstrlenA(buff
) - lstrlenA(buff3
)) == 0,
1858 "expected (%s), got (%s) for time part\n",
1859 buff3
, buff
+ lstrlenA(buff
) - lstrlenA(buff3
));
1860 ret
= GetDateFormatA(LOCALE_USER_DEFAULT
, DATE_LONGDATE
, &st
, NULL
, buff2
, sizeof(buff2
));
1861 ok(ret
== lstrlenA(buff2
)+1, "got %d\n", ret
);
1862 buff
[lstrlenA(buff2
)] = '\0';
1863 ok(lstrcmpA(buff2
, buff
) == 0, "expected (%s) got (%s) for date part\n",
1866 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_SHORTDATE
| FDTF_SHORTTIME
;
1867 ret
= pSHFormatDateTimeA(&filetime
, &flags
, buff
, sizeof(buff
));
1868 ok(ret
== lstrlenA(buff
)+1, "got %d\n", ret
);
1869 ret
= GetDateFormatA(LOCALE_USER_DEFAULT
, DATE_SHORTDATE
, &st
, NULL
, buff2
, sizeof(buff2
));
1870 ok(ret
== lstrlenA(buff2
)+1, "got %d\n", ret
);
1872 ret
= GetTimeFormatA(LOCALE_USER_DEFAULT
, TIME_NOSECONDS
, &st
, NULL
, buff3
, sizeof(buff3
));
1873 ok(ret
== lstrlenA(buff3
)+1, "got %d\n", ret
);
1874 strcat(buff2
, buff3
);
1875 ok(lstrcmpA(buff
, buff2
) == 0, "expected (%s), got (%s)\n", buff2
, buff
);
1877 flags
= FDTF_NOAUTOREADINGORDER
| FDTF_SHORTDATE
| FDTF_LONGTIME
;
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
, 0, &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
);
1889 static void test_SHFormatDateTimeW(void)
1891 FILETIME UNALIGNED filetime
;
1892 WCHAR buff
[100], buff2
[100], buff3
[100], *p1
, *p2
;
1896 static const WCHAR spaceW
[] = {' ',0};
1897 #define UNICODE_LTR_MARK 0x200e
1898 #define UNICODE_RTL_MARK 0x200f
1900 if(!pSHFormatDateTimeW
)
1902 win_skip("pSHFormatDateTimeW isn't available\n");
1908 /* crashes on native */
1909 pSHFormatDateTimeW(NULL
, NULL
, NULL
, 0);
1913 SystemTimeToFileTime(&st
, &filetime
);
1914 /* SHFormatDateTime expects input as utc */
1915 LocalFileTimeToFileTime(&filetime
, &filetime
);
1917 /* no way to get required buffer length here */
1918 SetLastError(0xdeadbeef);
1919 ret
= pSHFormatDateTimeW(&filetime
, NULL
, NULL
, 0);
1920 ok(ret
== 0, "expected 0, got %d\n", ret
);
1921 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1923 SetLastError(0xdeadbeef);
1924 buff
[0] = 'a'; buff
[1] = 0;
1925 ret
= pSHFormatDateTimeW(&filetime
, NULL
, buff
, 0);
1926 ok(ret
== 0, "expected 0, got %d\n", ret
);
1927 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1928 ok(buff
[0] == 'a', "expected same string\n");
1930 /* all combinations documented as invalid succeeded */
1931 flags
= FDTF_SHORTTIME
| FDTF_LONGTIME
;
1932 SetLastError(0xdeadbeef);
1933 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
1934 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
1935 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
1936 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1938 flags
= FDTF_SHORTDATE
| FDTF_LONGDATE
;
1939 SetLastError(0xdeadbeef);
1940 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
1941 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
1942 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
1943 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1945 flags
= FDTF_SHORTDATE
| FDTF_LTRDATE
| FDTF_RTLDATE
;
1946 SetLastError(0xdeadbeef);
1947 buff
[0] = 0; /* NT4 doesn't clear the buffer on failure */
1948 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
1949 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
1950 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
1951 ok(GetLastError() == 0xdeadbeef ||
1952 broken(GetLastError() == ERROR_INVALID_FLAGS
), /* Win9x/WinMe/NT4 */
1953 "expected 0xdeadbeef, got %d\n", GetLastError());
1955 /* now check returned strings */
1956 flags
= FDTF_SHORTTIME
;
1957 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
1958 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
1959 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
1960 SetLastError(0xdeadbeef);
1961 ret
= GetTimeFormatW(LOCALE_USER_DEFAULT
, TIME_NOSECONDS
, &st
, NULL
, buff2
, sizeof(buff2
)/sizeof(WCHAR
));
1962 if (ret
== 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1964 win_skip("Needed W-functions are not implemented\n");
1967 ok(ret
== lstrlenW(buff2
)+1, "expected %d, got %d\n", lstrlenW(buff2
)+1, ret
);
1968 ok(lstrcmpW(buff
, buff2
) == 0, "expected equal strings\n");
1970 flags
= FDTF_LONGTIME
;
1971 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
1972 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
1973 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
1974 ret
= GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, &st
, NULL
, buff2
, sizeof(buff2
)/sizeof(WCHAR
));
1975 ok(ret
== lstrlenW(buff2
)+1, "expected %d, got %d\n", lstrlenW(buff2
)+1, ret
);
1976 ok(lstrcmpW(buff
, buff2
) == 0, "expected equal strings\n");
1978 /* both time flags */
1979 flags
= FDTF_LONGTIME
| FDTF_SHORTTIME
;
1980 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
1981 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
1982 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
1983 ret
= GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, &st
, NULL
, buff2
, sizeof(buff2
)/sizeof(WCHAR
));
1984 ok(ret
== lstrlenW(buff2
)+1, "expected %d, got %d\n", lstrlenW(buff2
)+1, ret
);
1985 ok(lstrcmpW(buff
, buff2
) == 0, "expected equal string\n");
1987 flags
= FDTF_SHORTDATE
;
1988 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
1989 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
1990 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
1991 ret
= GetDateFormatW(LOCALE_USER_DEFAULT
, DATE_SHORTDATE
, &st
, NULL
, buff2
, sizeof(buff2
)/sizeof(WCHAR
));
1992 ok(ret
== lstrlenW(buff2
)+1, "expected %d, got %d\n", lstrlenW(buff2
)+1, ret
);
1993 ok(lstrcmpW(buff
, buff2
) == 0, "expected equal strings\n");
1995 flags
= FDTF_LONGDATE
;
1996 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
1997 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
1998 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
1999 ret
= GetDateFormatW(LOCALE_USER_DEFAULT
, DATE_LONGDATE
, &st
, NULL
, buff2
, sizeof(buff2
)/sizeof(WCHAR
));
2000 ok(ret
== lstrlenW(buff2
)+1, "expected %d, got %d\n", lstrlenW(buff2
)+1, ret
);
2001 ok(lstrcmpW(buff
, buff2
) == 0, "expected equal strings\n");
2003 /* both date flags */
2004 flags
= FDTF_LONGDATE
| FDTF_SHORTDATE
;
2005 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
2006 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
2007 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
2008 ret
= GetDateFormatW(LOCALE_USER_DEFAULT
, DATE_LONGDATE
, &st
, NULL
, buff2
, sizeof(buff2
)/sizeof(WCHAR
));
2009 ok(ret
== lstrlenW(buff2
)+1, "expected %d, got %d\n", lstrlenW(buff2
)+1, ret
);
2010 ok(lstrcmpW(buff
, buff2
) == 0, "expected equal strings\n");
2012 /* various combinations of date/time flags */
2013 flags
= FDTF_LONGDATE
| FDTF_SHORTTIME
;
2014 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
2015 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
2016 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
2017 ret
= GetTimeFormatW(LOCALE_USER_DEFAULT
, TIME_NOSECONDS
, &st
, NULL
, buff3
, sizeof(buff3
)/sizeof(WCHAR
));
2018 ok(ret
== lstrlenW(buff3
)+1, "expected %d, got %d\n", lstrlenW(buff3
)+1, ret
);
2019 ok(lstrcmpW(buff3
, buff
+ lstrlenW(buff
) - lstrlenW(buff3
)) == 0,
2020 "expected (%s), got (%s) for time part\n",
2021 wine_dbgstr_w(buff3
), wine_dbgstr_w(buff
+ lstrlenW(buff
) - lstrlenW(buff3
)));
2022 ret
= GetDateFormatW(LOCALE_USER_DEFAULT
, DATE_LONGDATE
, &st
, NULL
, buff2
, sizeof(buff2
)/sizeof(WCHAR
));
2023 ok(ret
== lstrlenW(buff2
)+1, "expected %d, got %d\n", lstrlenW(buff2
)+1, ret
);
2028 while (*p1
== UNICODE_LTR_MARK
|| *p1
== UNICODE_RTL_MARK
)
2030 while (*p2
== UNICODE_LTR_MARK
|| *p2
== UNICODE_RTL_MARK
)
2036 ok(lstrcmpW(buff2
, buff
) == 0, "expected (%s) got (%s) for date part\n",
2037 wine_dbgstr_w(buff2
), wine_dbgstr_w(buff
));
2039 flags
= FDTF_LONGDATE
| FDTF_LONGTIME
;
2040 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
2041 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
2042 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
2043 ret
= GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, &st
, NULL
, buff3
, sizeof(buff3
)/sizeof(WCHAR
));
2044 ok(ret
== lstrlenW(buff3
)+1, "expected %d, got %d\n", lstrlenW(buff3
)+1, ret
);
2045 ok(lstrcmpW(buff3
, buff
+ lstrlenW(buff
) - lstrlenW(buff3
)) == 0,
2046 "expected (%s), got (%s) for time part\n",
2047 wine_dbgstr_w(buff3
), wine_dbgstr_w(buff
+ lstrlenW(buff
) - lstrlenW(buff3
)));
2048 ret
= GetDateFormatW(LOCALE_USER_DEFAULT
, DATE_LONGDATE
, &st
, NULL
, buff2
, sizeof(buff2
)/sizeof(WCHAR
));
2049 ok(ret
== lstrlenW(buff2
)+1, "expected %d, got %d\n", lstrlenW(buff2
)+1, ret
);
2054 while (*p1
== UNICODE_LTR_MARK
|| *p1
== UNICODE_RTL_MARK
)
2056 while (*p2
== UNICODE_LTR_MARK
|| *p2
== UNICODE_RTL_MARK
)
2062 ok(lstrcmpW(buff2
, buff
) == 0, "expected (%s) got (%s) for date part\n",
2063 wine_dbgstr_w(buff2
), wine_dbgstr_w(buff
));
2065 flags
= FDTF_SHORTDATE
| FDTF_SHORTTIME
;
2066 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
2067 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
2068 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
2069 ret
= GetDateFormatW(LOCALE_USER_DEFAULT
, DATE_SHORTDATE
, &st
, NULL
, buff2
, sizeof(buff2
)/sizeof(WCHAR
));
2070 ok(ret
== lstrlenW(buff2
)+1, "expected %d, got %d\n", lstrlenW(buff2
)+1, ret
);
2071 lstrcatW(buff2
, spaceW
);
2072 ret
= GetTimeFormatW(LOCALE_USER_DEFAULT
, TIME_NOSECONDS
, &st
, NULL
, buff3
, sizeof(buff3
)/sizeof(WCHAR
));
2073 ok(ret
== lstrlenW(buff3
)+1, "expected %d, got %d\n", lstrlenW(buff3
)+1, ret
);
2074 lstrcatW(buff2
, buff3
);
2075 ok(lstrcmpW(buff
, buff2
) == 0, "expected equal strings\n");
2077 flags
= FDTF_SHORTDATE
| FDTF_LONGTIME
;
2078 ret
= pSHFormatDateTimeW(&filetime
, &flags
, buff
, sizeof(buff
)/sizeof(WCHAR
));
2079 ok(ret
== lstrlenW(buff
)+1 || ret
== lstrlenW(buff
),
2080 "expected %d or %d, got %d\n", lstrlenW(buff
)+1, lstrlenW(buff
), ret
);
2081 ret
= GetDateFormatW(LOCALE_USER_DEFAULT
, DATE_SHORTDATE
, &st
, NULL
, buff2
, sizeof(buff2
)/sizeof(WCHAR
));
2082 ok(ret
== lstrlenW(buff2
)+1, "expected %d, got %d\n", lstrlenW(buff2
)+1, ret
);
2083 lstrcatW(buff2
, spaceW
);
2084 ret
= GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, &st
, NULL
, buff3
, sizeof(buff3
)/sizeof(WCHAR
));
2085 ok(ret
== lstrlenW(buff3
)+1, "expected %d, got %d\n", lstrlenW(buff3
)+1, ret
);
2086 lstrcatW(buff2
, buff3
);
2087 ok(lstrcmpW(buff
, buff2
) == 0, "expected equal strings\n");
2090 static void test_SHGetObjectCompatFlags(void)
2092 struct compat_value
{
2097 struct compat_value values
[] = {
2098 { "OTNEEDSSFCACHE", 0x1 },
2099 { "NO_WEBVIEW", 0x2 },
2100 { "UNBINDABLE", 0x4 },
2102 { "NEEDSFILESYSANCESTOR", 0x10 },
2103 { "NOTAFILESYSTEM", 0x20 },
2104 { "CTXMENU_NOVERBS", 0x40 },
2105 { "CTXMENU_LIMITEDQI", 0x80 },
2106 { "COCREATESHELLFOLDERONLY", 0x100 },
2107 { "NEEDSSTORAGEANCESTOR", 0x200 },
2108 { "NOLEGACYWEBVIEW", 0x400 },
2109 { "CTXMENU_XPQCMFLAGS", 0x1000 },
2110 { "NOIPROPERTYSTORE", 0x2000 }
2113 static const char compat_path
[] = "Software\\Microsoft\\Windows\\CurrentVersion\\ShellCompatibility\\Objects";
2114 void *pColorAdjustLuma
= GetProcAddress(hShlwapi
, "ColorAdjustLuma");
2115 CHAR keyA
[39]; /* {CLSID} */
2120 if (!pSHGetObjectCompatFlags
)
2122 win_skip("SHGetObjectCompatFlags isn't available\n");
2126 if (pColorAdjustLuma
&& pColorAdjustLuma
== pSHGetObjectCompatFlags
) /* win2k */
2128 win_skip("Skipping SHGetObjectCompatFlags, same ordinal used for ColorAdjustLuma\n");
2133 ret
= pSHGetObjectCompatFlags(NULL
, NULL
);
2134 ok(ret
== 0, "got %d\n", ret
);
2136 ret
= RegOpenKeyA(HKEY_LOCAL_MACHINE
, compat_path
, &root
);
2137 if (ret
!= ERROR_SUCCESS
)
2139 skip("No compatibility class data found\n");
2143 for (i
= 0; RegEnumKeyA(root
, i
, keyA
, sizeof(keyA
)) == ERROR_SUCCESS
; i
++)
2147 if (RegOpenKeyA(root
, keyA
, &clsid_key
) == ERROR_SUCCESS
)
2150 DWORD expected
= 0, got
, length
= sizeof(valueA
);
2154 for (v
= 0; RegEnumValueA(clsid_key
, v
, valueA
, &length
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
; v
++)
2158 for (j
= 0; j
< sizeof(values
)/sizeof(struct compat_value
); j
++)
2159 if (lstrcmpA(values
[j
].nameA
, valueA
) == 0)
2161 expected
|= values
[j
].value
;
2165 length
= sizeof(valueA
);
2168 pGUIDFromStringA(keyA
, &clsid
);
2169 got
= pSHGetObjectCompatFlags(NULL
, &clsid
);
2170 ok(got
== expected
, "got 0x%08x, expected 0x%08x. Key %s\n", got
, expected
, keyA
);
2172 RegCloseKey(clsid_key
);
2180 IOleCommandTarget IOleCommandTarget_iface
;
2182 } IOleCommandTargetImpl
;
2184 static inline IOleCommandTargetImpl
*impl_from_IOleCommandTarget(IOleCommandTarget
*iface
)
2186 return CONTAINING_RECORD(iface
, IOleCommandTargetImpl
, IOleCommandTarget_iface
);
2189 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl
;
2191 static IOleCommandTarget
* IOleCommandTargetImpl_Construct(void)
2193 IOleCommandTargetImpl
*obj
;
2195 obj
= HeapAlloc(GetProcessHeap(), 0, sizeof(*obj
));
2196 obj
->IOleCommandTarget_iface
.lpVtbl
= &IOleCommandTargetImpl_Vtbl
;
2199 return &obj
->IOleCommandTarget_iface
;
2202 static HRESULT WINAPI
IOleCommandTargetImpl_QueryInterface(IOleCommandTarget
*iface
, REFIID riid
, void **ppvObj
)
2204 IOleCommandTargetImpl
*This
= impl_from_IOleCommandTarget(iface
);
2206 if (IsEqualIID(riid
, &IID_IUnknown
) ||
2207 IsEqualIID(riid
, &IID_IOleCommandTarget
))
2214 IOleCommandTarget_AddRef(iface
);
2218 return E_NOINTERFACE
;
2221 static ULONG WINAPI
IOleCommandTargetImpl_AddRef(IOleCommandTarget
*iface
)
2223 IOleCommandTargetImpl
*This
= impl_from_IOleCommandTarget(iface
);
2224 return InterlockedIncrement(&This
->ref
);
2227 static ULONG WINAPI
IOleCommandTargetImpl_Release(IOleCommandTarget
*iface
)
2229 IOleCommandTargetImpl
*This
= impl_from_IOleCommandTarget(iface
);
2230 ULONG ref
= InterlockedDecrement(&This
->ref
);
2234 HeapFree(GetProcessHeap(), 0, This
);
2240 static HRESULT WINAPI
IOleCommandTargetImpl_QueryStatus(
2241 IOleCommandTarget
*iface
, const GUID
*group
, ULONG cCmds
, OLECMD prgCmds
[], OLECMDTEXT
*pCmdText
)
2246 static HRESULT WINAPI
IOleCommandTargetImpl_Exec(
2247 IOleCommandTarget
*iface
,
2248 const GUID
*CmdGroup
,
2254 add_call(&trace_got
, 3, CmdGroup
, (void*)(DWORD_PTR
)nCmdID
, (void*)(DWORD_PTR
)nCmdexecopt
, pvaIn
, pvaOut
);
2258 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl
=
2260 IOleCommandTargetImpl_QueryInterface
,
2261 IOleCommandTargetImpl_AddRef
,
2262 IOleCommandTargetImpl_Release
,
2263 IOleCommandTargetImpl_QueryStatus
,
2264 IOleCommandTargetImpl_Exec
2268 IServiceProvider IServiceProvider_iface
;
2270 } IServiceProviderImpl
;
2272 static inline IServiceProviderImpl
*impl_from_IServiceProvider(IServiceProvider
*iface
)
2274 return CONTAINING_RECORD(iface
, IServiceProviderImpl
, IServiceProvider_iface
);
2278 IProfferService IProfferService_iface
;
2280 } IProfferServiceImpl
;
2282 static inline IProfferServiceImpl
*impl_from_IProfferService(IProfferService
*iface
)
2284 return CONTAINING_RECORD(iface
, IProfferServiceImpl
, IProfferService_iface
);
2288 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl
;
2289 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl
;
2291 static IServiceProvider
* IServiceProviderImpl_Construct(void)
2293 IServiceProviderImpl
*obj
;
2295 obj
= HeapAlloc(GetProcessHeap(), 0, sizeof(*obj
));
2296 obj
->IServiceProvider_iface
.lpVtbl
= &IServiceProviderImpl_Vtbl
;
2299 return &obj
->IServiceProvider_iface
;
2302 static IProfferService
* IProfferServiceImpl_Construct(void)
2304 IProfferServiceImpl
*obj
;
2306 obj
= HeapAlloc(GetProcessHeap(), 0, sizeof(*obj
));
2307 obj
->IProfferService_iface
.lpVtbl
= &IProfferServiceImpl_Vtbl
;
2310 return &obj
->IProfferService_iface
;
2313 static HRESULT WINAPI
IServiceProviderImpl_QueryInterface(IServiceProvider
*iface
, REFIID riid
, void **ppvObj
)
2315 IServiceProviderImpl
*This
= impl_from_IServiceProvider(iface
);
2317 if (IsEqualIID(riid
, &IID_IUnknown
) ||
2318 IsEqualIID(riid
, &IID_IServiceProvider
))
2325 IServiceProvider_AddRef(iface
);
2326 /* native uses redefined IID_IServiceProvider symbol, so we can't compare pointers */
2327 if (IsEqualIID(riid
, &IID_IServiceProvider
))
2328 add_call(&trace_got
, 1, iface
, &IID_IServiceProvider
, 0, 0, 0);
2332 return E_NOINTERFACE
;
2335 static ULONG WINAPI
IServiceProviderImpl_AddRef(IServiceProvider
*iface
)
2337 IServiceProviderImpl
*This
= impl_from_IServiceProvider(iface
);
2338 return InterlockedIncrement(&This
->ref
);
2341 static ULONG WINAPI
IServiceProviderImpl_Release(IServiceProvider
*iface
)
2343 IServiceProviderImpl
*This
= impl_from_IServiceProvider(iface
);
2344 ULONG ref
= InterlockedDecrement(&This
->ref
);
2348 HeapFree(GetProcessHeap(), 0, This
);
2354 static HRESULT WINAPI
IServiceProviderImpl_QueryService(
2355 IServiceProvider
*iface
, REFGUID service
, REFIID riid
, void **ppv
)
2357 /* native uses redefined pointer for IID_IOleCommandTarget, not one from uuid.lib */
2358 if (IsEqualIID(riid
, &IID_IOleCommandTarget
))
2360 add_call(&trace_got
, 2, iface
, service
, &IID_IOleCommandTarget
, 0, 0);
2361 *ppv
= IOleCommandTargetImpl_Construct();
2363 if (IsEqualIID(riid
, &IID_IProfferService
))
2365 if (IsEqualIID(service
, &IID_IProfferService
))
2366 add_call(&trace_got
, 2, &IID_IProfferService
, &IID_IProfferService
, 0, 0, 0);
2367 *ppv
= IProfferServiceImpl_Construct();
2372 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl
=
2374 IServiceProviderImpl_QueryInterface
,
2375 IServiceProviderImpl_AddRef
,
2376 IServiceProviderImpl_Release
,
2377 IServiceProviderImpl_QueryService
2380 static void test_IUnknown_QueryServiceExec(void)
2382 IServiceProvider
*provider
;
2383 static const GUID dummy_serviceid
= { 0xdeadbeef };
2384 static const GUID dummy_groupid
= { 0xbeefbeef };
2385 call_trace_t trace_expected
;
2388 /* on <=W2K platforms same ordinal used for another export with different
2389 prototype, so skipping using this indirect condition */
2390 if (is_win2k_and_lower
)
2392 win_skip("IUnknown_QueryServiceExec is not available\n");
2396 provider
= IServiceProviderImpl_Construct();
2398 /* null source pointer */
2399 hr
= pIUnknown_QueryServiceExec(NULL
, &dummy_serviceid
, &dummy_groupid
, 0, 0, 0, 0);
2401 hr
== E_NOTIMPL
, /* win 8 */
2402 "got 0x%08x\n", hr
);
2405 IUnknown_QueryServiceExec( ptr1, serviceid, groupid, arg1, arg2, arg3, arg4);
2406 -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &prov );
2407 -> IServiceProvider_QueryService( prov, serviceid, &IID_IOleCommandTarget, &obj );
2408 -> IOleCommandTarget_Exec( obj, groupid, arg1, arg2, arg3, arg4 );
2410 init_call_trace(&trace_expected
);
2412 add_call(&trace_expected
, 1, provider
, &IID_IServiceProvider
, 0, 0, 0);
2413 add_call(&trace_expected
, 2, provider
, &dummy_serviceid
, &IID_IOleCommandTarget
, 0, 0);
2414 add_call(&trace_expected
, 3, &dummy_groupid
, (void*)0x1, (void*)0x2, (void*)0x3, (void*)0x4);
2416 init_call_trace(&trace_got
);
2417 hr
= pIUnknown_QueryServiceExec((IUnknown
*)provider
, &dummy_serviceid
, &dummy_groupid
, 0x1, 0x2, (void*)0x3, (void*)0x4);
2418 ok(hr
== S_OK
, "got 0x%08x\n", hr
);
2420 ok_trace(&trace_expected
, &trace_got
);
2422 free_call_trace(&trace_expected
);
2423 free_call_trace(&trace_got
);
2425 IServiceProvider_Release(provider
);
2429 static HRESULT WINAPI
IProfferServiceImpl_QueryInterface(IProfferService
*iface
, REFIID riid
, void **ppvObj
)
2431 IProfferServiceImpl
*This
= impl_from_IProfferService(iface
);
2433 if (IsEqualIID(riid
, &IID_IUnknown
) ||
2434 IsEqualIID(riid
, &IID_IProfferService
))
2438 else if (IsEqualIID(riid
, &IID_IServiceProvider
))
2440 *ppvObj
= IServiceProviderImpl_Construct();
2441 add_call(&trace_got
, 1, iface
, &IID_IServiceProvider
, 0, 0, 0);
2447 IProfferService_AddRef(iface
);
2451 return E_NOINTERFACE
;
2454 static ULONG WINAPI
IProfferServiceImpl_AddRef(IProfferService
*iface
)
2456 IProfferServiceImpl
*This
= impl_from_IProfferService(iface
);
2457 return InterlockedIncrement(&This
->ref
);
2460 static ULONG WINAPI
IProfferServiceImpl_Release(IProfferService
*iface
)
2462 IProfferServiceImpl
*This
= impl_from_IProfferService(iface
);
2463 ULONG ref
= InterlockedDecrement(&This
->ref
);
2467 HeapFree(GetProcessHeap(), 0, This
);
2473 static HRESULT WINAPI
IProfferServiceImpl_ProfferService(IProfferService
*iface
,
2474 REFGUID service
, IServiceProvider
*pService
, DWORD
*pCookie
)
2476 *pCookie
= 0xdeadbeef;
2477 add_call(&trace_got
, 3, service
, pService
, pCookie
, 0, 0);
2481 static HRESULT WINAPI
IProfferServiceImpl_RevokeService(IProfferService
*iface
, DWORD cookie
)
2483 add_call(&trace_got
, 4, (void*)(DWORD_PTR
)cookie
, 0, 0, 0, 0);
2487 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl
=
2489 IProfferServiceImpl_QueryInterface
,
2490 IProfferServiceImpl_AddRef
,
2491 IProfferServiceImpl_Release
,
2492 IProfferServiceImpl_ProfferService
,
2493 IProfferServiceImpl_RevokeService
2496 static void test_IUnknown_ProfferService(void)
2498 IServiceProvider
*provider
;
2499 IProfferService
*proff
;
2500 static const GUID dummy_serviceid
= { 0xdeadbeef };
2501 call_trace_t trace_expected
;
2505 /* on <=W2K platforms same ordinal used for another export with different
2506 prototype, so skipping using this indirect condition */
2507 if (is_win2k_and_lower
)
2509 win_skip("IUnknown_ProfferService is not available\n");
2513 provider
= IServiceProviderImpl_Construct();
2514 proff
= IProfferServiceImpl_Construct();
2516 /* null source pointer */
2517 hr
= pIUnknown_ProfferService(NULL
, &dummy_serviceid
, 0, 0);
2519 hr
== E_NOTIMPL
, /* win 8 */
2520 "got 0x%08x\n", hr
);
2523 IUnknown_ProfferService( ptr1, serviceid, arg1, arg2);
2524 -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &provider );
2525 -> IServiceProvider_QueryService( provider, &IID_IProfferService, &IID_IProfferService, &proffer );
2527 if (service pointer not null):
2528 -> IProfferService_ProfferService( proffer, serviceid, arg1, arg2 );
2530 -> IProfferService_RevokeService( proffer, *arg2 );
2532 init_call_trace(&trace_expected
);
2534 add_call(&trace_expected
, 1, proff
, &IID_IServiceProvider
, 0, 0, 0);
2535 add_call(&trace_expected
, 2, &IID_IProfferService
, &IID_IProfferService
, 0, 0, 0);
2536 add_call(&trace_expected
, 3, &dummy_serviceid
, provider
, &cookie
, 0, 0);
2538 init_call_trace(&trace_got
);
2540 hr
= pIUnknown_ProfferService((IUnknown
*)proff
, &dummy_serviceid
, provider
, &cookie
);
2541 ok(hr
== S_OK
, "got 0x%08x\n", hr
);
2542 ok(cookie
== 0xdeadbeef, "got %x\n", cookie
);
2544 ok_trace(&trace_expected
, &trace_got
);
2545 free_call_trace(&trace_got
);
2546 free_call_trace(&trace_expected
);
2548 /* same with ::Revoke path */
2549 init_call_trace(&trace_expected
);
2551 add_call(&trace_expected
, 1, proff
, &IID_IServiceProvider
, 0, 0, 0);
2552 add_call(&trace_expected
, 2, &IID_IProfferService
, &IID_IProfferService
, 0, 0, 0);
2553 add_call(&trace_expected
, 4, (void*)(DWORD_PTR
)cookie
, 0, 0, 0, 0);
2555 init_call_trace(&trace_got
);
2556 ok(cookie
!= 0, "got %x\n", cookie
);
2557 hr
= pIUnknown_ProfferService((IUnknown
*)proff
, &dummy_serviceid
, 0, &cookie
);
2558 ok(hr
== S_OK
, "got 0x%08x\n", hr
);
2559 ok(cookie
== 0, "got %x\n", cookie
);
2560 ok_trace(&trace_expected
, &trace_got
);
2561 free_call_trace(&trace_got
);
2562 free_call_trace(&trace_expected
);
2564 IServiceProvider_Release(provider
);
2565 IProfferService_Release(proff
);
2568 static void test_SHCreateWorkerWindowA(void)
2576 if (is_win2k_and_lower
)
2578 win_skip("SHCreateWorkerWindowA not available\n");
2582 hwnd
= pSHCreateWorkerWindowA(0, NULL
, 0, 0, 0, 0);
2583 ok(hwnd
!= 0, "expected window\n");
2585 GetClassNameA(hwnd
, classA
, 20);
2586 ok(lstrcmpA(classA
, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA
);
2588 ret
= GetWindowLongPtrA(hwnd
, 0);
2589 ok(ret
== 0, "got %ld\n", ret
);
2592 memset(&cliA
, 0, sizeof(cliA
));
2593 res
= GetClassInfoA(GetModuleHandleA("shlwapi.dll"), "WorkerA", &cliA
);
2594 ok(res
, "failed to get class info\n");
2595 ok(cliA
.style
== 0, "got 0x%08x\n", cliA
.style
);
2596 ok(cliA
.cbClsExtra
== 0, "got %d\n", cliA
.cbClsExtra
);
2597 ok(cliA
.cbWndExtra
== sizeof(LONG_PTR
), "got %d\n", cliA
.cbWndExtra
);
2598 ok(cliA
.lpszMenuName
== 0, "got %s\n", cliA
.lpszMenuName
);
2600 DestroyWindow(hwnd
);
2602 /* set extra bytes */
2603 hwnd
= pSHCreateWorkerWindowA(0, NULL
, 0, 0, 0, 0xdeadbeef);
2604 ok(hwnd
!= 0, "expected window\n");
2606 GetClassNameA(hwnd
, classA
, 20);
2607 ok(lstrcmpA(classA
, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA
);
2609 ret
= GetWindowLongPtrA(hwnd
, 0);
2610 ok(ret
== 0xdeadbeef, "got %ld\n", ret
);
2613 ret
= GetWindowLongA(hwnd
, GWL_EXSTYLE
);
2614 ok(ret
== WS_EX_WINDOWEDGE
||
2615 ret
== (WS_EX_WINDOWEDGE
|WS_EX_LAYOUTRTL
) /* systems with RTL locale */, "0x%08lx\n", ret
);
2617 DestroyWindow(hwnd
);
2619 hwnd
= pSHCreateWorkerWindowA(0, NULL
, WS_EX_TOOLWINDOW
, 0, 0, 0);
2620 ret
= GetWindowLongA(hwnd
, GWL_EXSTYLE
);
2621 ok(ret
== (WS_EX_WINDOWEDGE
|WS_EX_TOOLWINDOW
) ||
2622 ret
== (WS_EX_WINDOWEDGE
|WS_EX_TOOLWINDOW
|WS_EX_LAYOUTRTL
) /* systems with RTL locale */, "0x%08lx\n", ret
);
2623 DestroyWindow(hwnd
);
2626 static HRESULT WINAPI
SF_QueryInterface(IShellFolder
*iface
,
2627 REFIID riid
, void **ppv
)
2629 /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */
2630 ok(!IsEqualGUID(&IID_IShellFolder
, riid
),
2631 "Unexpected QI for IShellFolder\n");
2632 return E_NOINTERFACE
;
2635 static ULONG WINAPI
SF_AddRef(IShellFolder
*iface
)
2640 static ULONG WINAPI
SF_Release(IShellFolder
*iface
)
2645 static HRESULT WINAPI
SF_ParseDisplayName(IShellFolder
*iface
,
2646 HWND owner
, LPBC reserved
, LPOLESTR displayName
, ULONG
*eaten
,
2647 LPITEMIDLIST
*idl
, ULONG
*attr
)
2649 ok(0, "Didn't expect ParseDisplayName\n");
2653 static HRESULT WINAPI
SF_EnumObjects(IShellFolder
*iface
,
2654 HWND owner
, SHCONTF flags
, IEnumIDList
**enm
)
2656 *enm
= (IEnumIDList
*)0xcafebabe;
2660 static HRESULT WINAPI
SF_BindToObject(IShellFolder
*iface
,
2661 LPCITEMIDLIST idl
, LPBC reserved
, REFIID riid
, void **obj
)
2663 ok(0, "Didn't expect BindToObject\n");
2667 static HRESULT WINAPI
SF_BindToStorage(IShellFolder
*iface
,
2668 LPCITEMIDLIST idl
, LPBC reserved
, REFIID riid
, void **obj
)
2670 ok(0, "Didn't expect BindToStorage\n");
2674 static HRESULT WINAPI
SF_CompareIDs(IShellFolder
*iface
,
2675 LPARAM lparam
, LPCITEMIDLIST idl1
, LPCITEMIDLIST idl2
)
2677 ok(0, "Didn't expect CompareIDs\n");
2681 static HRESULT WINAPI
SF_CreateViewObject(IShellFolder
*iface
,
2682 HWND owner
, REFIID riid
, void **out
)
2684 ok(0, "Didn't expect CreateViewObject\n");
2688 static HRESULT WINAPI
SF_GetAttributesOf(IShellFolder
*iface
,
2690 UINT cidl
, PCUITEMID_CHILD_ARRAY idl
, SFGAOF
*inOut
)
2692 UINT cidl
, LPCITEMIDLIST
*idl
, SFGAOF
*inOut
)
2695 ok(0, "Didn't expect GetAttributesOf\n");
2699 static HRESULT WINAPI
SF_GetUIObjectOf(IShellFolder
*iface
,
2701 HWND owner
, UINT cidl
, PCUITEMID_CHILD_ARRAY idls
, REFIID riid
, UINT
*inOut
,
2703 HWND owner
, UINT cidl
, LPCITEMIDLIST
*idls
, REFIID riid
, UINT
*inOut
,
2707 ok(0, "Didn't expect GetUIObjectOf\n");
2711 static HRESULT WINAPI
SF_GetDisplayNameOf(IShellFolder
*iface
,
2712 LPCITEMIDLIST idl
, SHGDNF flags
, STRRET
*name
)
2714 ok(0, "Didn't expect GetDisplayNameOf\n");
2718 static HRESULT WINAPI
SF_SetNameOf(IShellFolder
*iface
,
2719 HWND hwnd
, LPCITEMIDLIST idl
, LPCOLESTR name
, SHGDNF flags
,
2720 LPITEMIDLIST
*idlOut
)
2722 ok(0, "Didn't expect SetNameOf\n");
2726 static IShellFolderVtbl ShellFolderVtbl
= {
2730 SF_ParseDisplayName
,
2735 SF_CreateViewObject
,
2738 SF_GetDisplayNameOf
,
2742 static IShellFolder ShellFolder
= { &ShellFolderVtbl
};
2744 static void test_SHIShellFolder_EnumObjects(void)
2748 IShellFolder
*folder
;
2750 if(!pSHIShellFolder_EnumObjects
|| is_win2k_and_lower
){
2751 win_skip("SHIShellFolder_EnumObjects not available\n");
2756 /* NULL object crashes on Windows */
2757 pSHIShellFolder_EnumObjects(NULL
, NULL
, 0, NULL
);
2760 /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */
2761 enm
= (IEnumIDList
*)0xdeadbeef;
2762 hres
= pSHIShellFolder_EnumObjects(&ShellFolder
, NULL
, 0, &enm
);
2763 ok(hres
== S_OK
, "SHIShellFolder_EnumObjects failed: 0x%08x\n", hres
);
2764 ok(enm
== (IEnumIDList
*)0xcafebabe, "Didn't get expected enumerator location, instead: %p\n", enm
);
2766 /* SHIShellFolder_EnumObjects isn't strict about the IShellFolder object */
2767 hres
= pSHGetDesktopFolder(&folder
);
2768 ok(hres
== S_OK
, "SHGetDesktopFolder failed: 0x%08x\n", hres
);
2771 hres
= pSHIShellFolder_EnumObjects(folder
, NULL
, 0, &enm
);
2772 ok(hres
== S_OK
, "SHIShellFolder_EnumObjects failed: 0x%08x\n", hres
);
2773 ok(enm
!= NULL
, "Didn't get an enumerator\n");
2775 IEnumIDList_Release(enm
);
2777 IShellFolder_Release(folder
);
2780 static BOOL
write_inifile(LPCWSTR filename
)
2785 static const char data
[] =
2788 "AnotherKey=asdf\r\n";
2790 file
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
2791 if(file
== INVALID_HANDLE_VALUE
) {
2792 win_skip("failed to create ini file at %s\n", wine_dbgstr_w(filename
));
2796 WriteFile(file
, data
, sizeof(data
), &written
, NULL
);
2803 #define verify_inifile(f, e) r_verify_inifile(__LINE__, f, e)
2804 static void r_verify_inifile(unsigned l
, LPCWSTR filename
, LPCSTR exp
)
2810 file
= CreateFileW(filename
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
2812 if(file
== INVALID_HANDLE_VALUE
)
2815 ReadFile(file
, buf
, sizeof(buf
) * sizeof(CHAR
), &read
, NULL
);
2820 ok_(__FILE__
,l
)(!strcmp(buf
, exp
), "Expected:\n%s\nGot:\n%s\n", exp
,
2824 static void test_SHGetIniString(void)
2827 WCHAR out
[64] = {0};
2829 static const WCHAR TestAppW
[] = {'T','e','s','t','A','p','p',0};
2830 static const WCHAR AKeyW
[] = {'A','K','e','y',0};
2831 static const WCHAR AnotherKeyW
[] = {'A','n','o','t','h','e','r','K','e','y',0};
2832 static const WCHAR JunkKeyW
[] = {'J','u','n','k','K','e','y',0};
2833 static const WCHAR testpathW
[] = {'C',':','\\','t','e','s','t','.','i','n','i',0};
2834 WCHAR pathW
[MAX_PATH
];
2836 if(!pSHGetIniStringW
|| is_win2k_and_lower
){
2837 win_skip("SHGetIniStringW is not available\n");
2841 lstrcpyW(pathW
, testpathW
);
2843 if (!write_inifile(pathW
))
2847 /* these crash on Windows */
2848 pSHGetIniStringW(NULL
, NULL
, NULL
, 0, NULL
);
2849 pSHGetIniStringW(NULL
, AKeyW
, out
, sizeof(out
), pathW
);
2850 pSHGetIniStringW(TestAppW
, AKeyW
, NULL
, sizeof(out
), pathW
);
2853 ret
= pSHGetIniStringW(TestAppW
, AKeyW
, out
, 0, pathW
);
2854 ok(ret
== 0, "SHGetIniStringW should have given 0, instead: %d\n", ret
);
2856 /* valid arguments */
2858 SetLastError(0xdeadbeef);
2859 ret
= pSHGetIniStringW(TestAppW
, NULL
, out
, sizeof(out
), pathW
);
2860 ok(ret
== 4, "SHGetIniStringW should have given 4, instead: %d\n", ret
);
2861 ok(!lstrcmpW(out
, AKeyW
), "Expected %s, got: %s, %d\n",
2862 wine_dbgstr_w(AKeyW
), wine_dbgstr_w(out
), GetLastError());
2864 ret
= pSHGetIniStringW(TestAppW
, AKeyW
, out
, sizeof(out
), pathW
);
2865 ok(ret
== 1, "SHGetIniStringW should have given 1, instead: %d\n", ret
);
2866 ok(!strcmp_wa(out
, "1"), "Expected L\"1\", got: %s\n", wine_dbgstr_w(out
));
2868 ret
= pSHGetIniStringW(TestAppW
, AnotherKeyW
, out
, sizeof(out
), pathW
);
2869 ok(ret
== 4, "SHGetIniStringW should have given 4, instead: %d\n", ret
);
2870 ok(!strcmp_wa(out
, "asdf"), "Expected L\"asdf\", got: %s\n", wine_dbgstr_w(out
));
2873 ret
= pSHGetIniStringW(TestAppW
, JunkKeyW
, out
, sizeof(out
), pathW
);
2874 ok(ret
== 0, "SHGetIniStringW should have given 0, instead: %d\n", ret
);
2875 ok(*out
== 0, "Expected L\"\", got: %s\n", wine_dbgstr_w(out
));
2880 static void test_SHSetIniString(void)
2884 static const WCHAR TestAppW
[] = {'T','e','s','t','A','p','p',0};
2885 static const WCHAR AnotherAppW
[] = {'A','n','o','t','h','e','r','A','p','p',0};
2886 static const WCHAR TestIniW
[] = {'C',':','\\','t','e','s','t','.','i','n','i',0};
2887 static const WCHAR AKeyW
[] = {'A','K','e','y',0};
2888 static const WCHAR NewKeyW
[] = {'N','e','w','K','e','y',0};
2889 static const WCHAR AValueW
[] = {'A','V','a','l','u','e',0};
2891 if(!pSHSetIniStringW
|| is_win2k_and_lower
){
2892 win_skip("SHSetIniStringW is not available\n");
2896 if (!write_inifile(TestIniW
))
2899 ret
= pSHSetIniStringW(TestAppW
, AKeyW
, AValueW
, TestIniW
);
2900 ok(ret
== TRUE
, "SHSetIniStringW should not have failed\n");
2901 todo_wine
/* wine sticks an extra \r\n at the end of the file */
2902 verify_inifile(TestIniW
, "[TestApp]\r\nAKey=AValue\r\nAnotherKey=asdf\r\n");
2904 ret
= pSHSetIniStringW(TestAppW
, AKeyW
, NULL
, TestIniW
);
2905 ok(ret
== TRUE
, "SHSetIniStringW should not have failed\n");
2906 verify_inifile(TestIniW
, "[TestApp]\r\nAnotherKey=asdf\r\n");
2908 ret
= pSHSetIniStringW(AnotherAppW
, NewKeyW
, AValueW
, TestIniW
);
2909 ok(ret
== TRUE
, "SHSetIniStringW should not have failed\n");
2910 verify_inifile(TestIniW
, "[TestApp]\r\nAnotherKey=asdf\r\n[AnotherApp]\r\nNewKey=AValue\r\n");
2912 ret
= pSHSetIniStringW(TestAppW
, NULL
, AValueW
, TestIniW
);
2913 ok(ret
== TRUE
, "SHSetIniStringW should not have failed\n");
2914 verify_inifile(TestIniW
, "[AnotherApp]\r\nNewKey=AValue\r\n");
2916 DeleteFileW(TestIniW
);
2919 enum _shellkey_flags
{
2920 SHKEY_Root_HKCU
= 0x1,
2921 SHKEY_Root_HKLM
= 0x2,
2922 SHKEY_Key_Explorer
= 0x00,
2923 SHKEY_Key_Shell
= 0x10,
2924 SHKEY_Key_ShellNoRoam
= 0x20,
2925 SHKEY_Key_Classes
= 0x30,
2926 SHKEY_Subkey_Default
= 0x0000,
2927 SHKEY_Subkey_ResourceName
= 0x1000,
2928 SHKEY_Subkey_Handlers
= 0x2000,
2929 SHKEY_Subkey_Associations
= 0x3000,
2930 SHKEY_Subkey_Volatile
= 0x4000,
2931 SHKEY_Subkey_MUICache
= 0x5000,
2932 SHKEY_Subkey_FileExts
= 0x6000
2935 static void test_SHGetShellKey(void)
2937 static const WCHAR ShellFoldersW
[] = { 'S','h','e','l','l',' ','F','o','l','d','e','r','s',0 };
2938 static const WCHAR WineTestW
[] = { 'W','i','n','e','T','e','s','t',0 };
2940 void *pPathBuildRootW
= GetProcAddress(hShlwapi
, "PathBuildRootW");
2941 DWORD
*alloc_data
, data
, size
;
2945 if (!pSHGetShellKey
)
2947 win_skip("SHGetShellKey(ordinal 491) isn't available\n");
2952 if (pPathBuildRootW
&& pPathBuildRootW
== pSHGetShellKey
)
2954 win_skip("SHGetShellKey(ordinal 491) used for PathBuildRootW\n");
2958 if (is_win9x
|| is_win2k_and_lower
)
2960 win_skip("Ordinal 491 used for another call, skipping SHGetShellKey tests\n");
2964 /* Vista+ limits SHKEY enumeration values */
2965 SetLastError(0xdeadbeef);
2966 hkey
= pSHGetShellKey(SHKEY_Key_Explorer
, ShellFoldersW
, FALSE
);
2969 /* Tests not working on Vista+ */
2972 hkey
= pSHGetShellKey(SHKEY_Root_HKLM
|SHKEY_Key_Classes
, NULL
, FALSE
);
2973 ok(hkey
!= NULL
, "hkey = NULL\n");
2977 hkey
= pSHGetShellKey(SHKEY_Root_HKCU
|SHKEY_Key_Explorer
, ShellFoldersW
, FALSE
);
2978 ok(hkey
!= NULL
, "hkey = NULL\n");
2981 hkey
= pSHGetShellKey(SHKEY_Root_HKLM
|SHKEY_Key_Explorer
, ShellFoldersW
, FALSE
);
2982 ok(hkey
!= NULL
, "hkey = NULL\n");
2985 hkey
= pSHGetShellKey(SHKEY_Root_HKLM
, WineTestW
, FALSE
);
2986 ok(hkey
== NULL
, "hkey != NULL\n");
2988 hkey
= pSHGetShellKey(SHKEY_Root_HKLM
, NULL
, FALSE
);
2989 ok(hkey
!= NULL
, "Can't open key\n");
2990 ok(SUCCEEDED(RegDeleteKeyW(hkey
, WineTestW
)), "Can't delete key\n");
2993 hkey
= pSHGetShellKey(SHKEY_Root_HKLM
, WineTestW
, TRUE
);
2994 if (!hkey
&& GetLastError() == ERROR_ACCESS_DENIED
)
2996 skip("Not authorized to create keys\n");
2999 ok(hkey
!= NULL
, "Can't create key\n");
3002 if (!pSKGetValueW
|| !pSKSetValueW
|| !pSKDeleteValueW
|| !pSKAllocValueW
)
3004 win_skip("SKGetValueW, SKSetValueW, SKDeleteValueW or SKAllocValueW not available\n");
3008 size
= sizeof(data
);
3009 hres
= pSKGetValueW(SHKEY_Root_HKLM
, WineTestW
, NULL
, NULL
, &data
, &size
);
3010 ok(hres
== HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
), "hres = %x\n", hres
);
3013 hres
= pSKSetValueW(SHKEY_Root_HKLM
, WineTestW
, NULL
, REG_DWORD
, &data
, sizeof(DWORD
));
3014 ok(hres
== S_OK
, "hres = %x\n", hres
);
3017 hres
= pSKGetValueW(SHKEY_Root_HKLM
, WineTestW
, NULL
, NULL
, NULL
, &size
);
3018 ok(hres
== S_OK
, "hres = %x\n", hres
);
3019 ok(size
== sizeof(DWORD
), "size = %d\n", size
);
3022 hres
= pSKGetValueW(SHKEY_Root_HKLM
, WineTestW
, NULL
, NULL
, &data
, &size
);
3023 ok(hres
== S_OK
, "hres = %x\n", hres
);
3024 ok(size
== sizeof(DWORD
), "size = %d\n", size
);
3025 ok(data
== 1234, "data = %d\n", data
);
3027 hres
= pSKAllocValueW(SHKEY_Root_HKLM
, WineTestW
, NULL
, NULL
, (void**)&alloc_data
, &size
);
3028 ok(hres
== S_OK
, "hres= %x\n", hres
);
3029 ok(size
== sizeof(DWORD
), "size = %d\n", size
);
3030 if (SUCCEEDED(hres
))
3032 ok(*alloc_data
== 1234, "*alloc_data = %d\n", *alloc_data
);
3033 LocalFree(alloc_data
);
3036 hres
= pSKDeleteValueW(SHKEY_Root_HKLM
, WineTestW
, NULL
);
3037 ok(hres
== S_OK
, "hres = %x\n", hres
);
3039 hres
= pSKDeleteValueW(SHKEY_Root_HKLM
, WineTestW
, NULL
);
3040 ok(hres
== HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
), "hres = %x\n", hres
);
3042 hres
= pSKGetValueW(SHKEY_Root_HKLM
, WineTestW
, NULL
, NULL
, &data
, &size
);
3043 ok(hres
== HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
), "hres = %x\n", hres
);
3045 hkey
= pSHGetShellKey(SHKEY_Root_HKLM
, NULL
, FALSE
);
3046 ok(hkey
!= NULL
, "Can't create key\n");
3047 ok(SUCCEEDED(RegDeleteKeyW(hkey
, WineTestW
)), "Can't delete key\n");
3051 static void init_pointers(void)
3053 #define MAKEFUNC(f, ord) (p##f = (void*)GetProcAddress(hShlwapi, (LPSTR)(ord)))
3054 MAKEFUNC(SHAllocShared
, 7);
3055 MAKEFUNC(SHLockShared
, 8);
3056 MAKEFUNC(SHUnlockShared
, 9);
3057 MAKEFUNC(SHFreeShared
, 10);
3058 MAKEFUNC(SHMapHandle
, 11);
3059 MAKEFUNC(GetAcceptLanguagesA
, 14);
3060 MAKEFUNC(SHSetWindowBits
, 165);
3061 MAKEFUNC(SHSetParentHwnd
, 167);
3062 MAKEFUNC(ConnectToConnectionPoint
, 168);
3063 MAKEFUNC(IUnknown_GetClassID
, 175);
3064 MAKEFUNC(SHSearchMapInt
, 198);
3065 MAKEFUNC(SHCreateWorkerWindowA
, 257);
3066 MAKEFUNC(GUIDFromStringA
, 269);
3067 MAKEFUNC(SHPackDispParams
, 282);
3068 MAKEFUNC(IConnectionPoint_InvokeWithCancel
, 283);
3069 MAKEFUNC(IConnectionPoint_SimpleInvoke
, 284);
3070 MAKEFUNC(SHGetIniStringW
, 294);
3071 MAKEFUNC(SHSetIniStringW
, 295);
3072 MAKEFUNC(SHFormatDateTimeA
, 353);
3073 MAKEFUNC(SHFormatDateTimeW
, 354);
3074 MAKEFUNC(SHIShellFolder_EnumObjects
, 404);
3075 MAKEFUNC(SHGetObjectCompatFlags
, 476);
3076 MAKEFUNC(IUnknown_QueryServiceExec
, 484);
3077 MAKEFUNC(SHGetShellKey
, 491);
3078 MAKEFUNC(SHPropertyBag_ReadLONG
, 496);
3079 MAKEFUNC(IUnknown_ProfferService
, 514);
3080 MAKEFUNC(SKGetValueW
, 516);
3081 MAKEFUNC(SKSetValueW
, 517);
3082 MAKEFUNC(SKDeleteValueW
, 518);
3083 MAKEFUNC(SKAllocValueW
, 519);
3087 static void test_SHSetParentHwnd(void)
3089 HWND hwnd
, hwnd2
, ret
;
3092 if (!pSHSetParentHwnd
)
3094 win_skip("SHSetParentHwnd not available\n");
3098 hwnd
= CreateWindowA("Button", "", WS_VISIBLE
, 0, 0, 10, 10, NULL
, NULL
, NULL
, NULL
);
3099 ok(hwnd
!= NULL
, "got %p\n", hwnd
);
3101 hwnd2
= CreateWindowA("Button", "", WS_VISIBLE
| WS_CHILD
, 0, 0, 10, 10, hwnd
, NULL
, NULL
, NULL
);
3102 ok(hwnd2
!= NULL
, "got %p\n", hwnd2
);
3105 ret
= pSHSetParentHwnd(NULL
, NULL
);
3106 ok(ret
== NULL
, "got %p\n", ret
);
3108 /* set to no parent while already no parent present */
3109 ret
= GetParent(hwnd
);
3110 ok(ret
== NULL
, "got %p\n", ret
);
3111 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
3112 ok((style
& (WS_POPUP
|WS_CHILD
)) == 0, "got style 0x%08x\n", style
);
3113 ret
= pSHSetParentHwnd(hwnd
, NULL
);
3114 ok(ret
== NULL
, "got %p\n", ret
);
3115 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
3116 ok((style
& (WS_POPUP
|WS_CHILD
)) == 0, "got style 0x%08x\n", style
);
3118 /* reset to null parent from not null */
3119 ret
= GetParent(hwnd2
);
3120 ok(ret
== hwnd
, "got %p\n", ret
);
3121 style
= GetWindowLongA(hwnd2
, GWL_STYLE
);
3122 ok((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
, "got style 0x%08x\n", style
);
3123 ret
= pSHSetParentHwnd(hwnd2
, NULL
);
3124 ok(ret
== NULL
, "got %p\n", ret
);
3125 style
= GetWindowLongA(hwnd2
, GWL_STYLE
);
3126 ok((style
& (WS_POPUP
|WS_CHILD
)) == WS_POPUP
, "got style 0x%08x\n", style
);
3127 ret
= GetParent(hwnd2
);
3128 ok(ret
== NULL
, "got %p\n", ret
);
3130 /* set parent back */
3131 style
= GetWindowLongA(hwnd2
, GWL_STYLE
);
3132 SetWindowLongA(hwnd2
, GWL_STYLE
, style
& ~(WS_CHILD
|WS_POPUP
));
3133 style
= GetWindowLongA(hwnd2
, GWL_STYLE
);
3134 ok((style
& (WS_CHILD
|WS_POPUP
)) == 0, "got 0x%08x\n", style
);
3136 ret
= pSHSetParentHwnd(hwnd2
, hwnd
);
3137 todo_wine
ok(ret
== NULL
, "got %p\n", ret
);
3139 style
= GetWindowLongA(hwnd2
, GWL_STYLE
);
3140 ok((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
, "got style 0x%08x\n", style
);
3141 ret
= GetParent(hwnd2
);
3142 ok(ret
== hwnd
, "got %p\n", ret
);
3144 /* try to set same parent again */
3146 style
= GetWindowLongA(hwnd2
, GWL_STYLE
);
3147 SetWindowLongA(hwnd2
, GWL_STYLE
, style
| WS_POPUP
);
3148 ret
= pSHSetParentHwnd(hwnd2
, hwnd
);
3149 todo_wine
ok(ret
== NULL
, "got %p\n", ret
);
3150 style
= GetWindowLongA(hwnd2
, GWL_STYLE
);
3151 ok((style
& (WS_CHILD
|WS_POPUP
)) == WS_CHILD
, "got 0x%08x\n", style
);
3152 ret
= GetParent(hwnd2
);
3153 ok(ret
== hwnd
, "got %p\n", ret
);
3155 /* without WS_POPUP */
3156 style
= GetWindowLongA(hwnd2
, GWL_STYLE
);
3157 SetWindowLongA(hwnd2
, GWL_STYLE
, style
| ~WS_POPUP
);
3158 ret
= pSHSetParentHwnd(hwnd2
, hwnd
);
3159 todo_wine
ok(ret
== hwnd
, "got %p\n", ret
);
3160 style
= GetWindowLongA(hwnd2
, GWL_STYLE
);
3161 ok((style
& (WS_CHILD
|WS_POPUP
)) == WS_CHILD
, "got 0x%08x\n", style
);
3162 ret
= GetParent(hwnd2
);
3163 ok(ret
== hwnd
, "got %p\n", ret
);
3165 DestroyWindow(hwnd
);
3166 DestroyWindow(hwnd2
);
3169 static HRESULT WINAPI
testpersist_QI(IPersist
*iface
, REFIID riid
, void **obj
)
3171 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IPersist
)) {
3173 IPersist_AddRef(iface
);
3178 return E_NOINTERFACE
;
3181 static HRESULT WINAPI
testpersist_QI2(IPersist
*iface
, REFIID riid
, void **obj
)
3183 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IPersistFolder
)) {
3185 IPersist_AddRef(iface
);
3190 return E_NOINTERFACE
;
3193 static ULONG WINAPI
testpersist_AddRef(IPersist
*iface
)
3198 static ULONG WINAPI
testpersist_Release(IPersist
*iface
)
3203 static HRESULT WINAPI
testpersist_GetClassID(IPersist
*iface
, CLSID
*clsid
)
3205 memset(clsid
, 0xab, sizeof(*clsid
));
3209 static IPersistVtbl testpersistvtbl
= {
3212 testpersist_Release
,
3213 testpersist_GetClassID
3216 static IPersistVtbl testpersist2vtbl
= {
3219 testpersist_Release
,
3220 testpersist_GetClassID
3223 static IPersist testpersist
= { &testpersistvtbl
};
3224 static IPersist testpersist2
= { &testpersist2vtbl
};
3226 static void test_IUnknown_GetClassID(void)
3228 CLSID clsid
, clsid2
, clsid3
;
3231 if (0) /* crashes on native systems */
3232 hr
= pIUnknown_GetClassID(NULL
, NULL
);
3234 memset(&clsid
, 0xcc, sizeof(clsid
));
3235 memset(&clsid3
, 0xcc, sizeof(clsid3
));
3236 hr
= pIUnknown_GetClassID(NULL
, &clsid
);
3237 ok(hr
== E_FAIL
, "got 0x%08x\n", hr
);
3238 ok(IsEqualCLSID(&clsid
, &CLSID_NULL
) || broken(IsEqualCLSID(&clsid
, &clsid3
)) /* win2k, winxp, win2k3 */,
3239 "got wrong clsid %s\n", wine_dbgstr_guid(&clsid
));
3241 memset(&clsid
, 0xcc, sizeof(clsid
));
3242 memset(&clsid2
, 0xab, sizeof(clsid2
));
3243 hr
= pIUnknown_GetClassID((IUnknown
*)&testpersist
, &clsid
);
3244 ok(hr
== 0x8fff2222, "got 0x%08x\n", hr
);
3245 ok(IsEqualCLSID(&clsid
, &clsid2
) || broken(IsEqualCLSID(&clsid
, &clsid3
)) /* win2k3 */,
3246 "got wrong clsid %s\n", wine_dbgstr_guid(&clsid
));
3248 /* IPersistFolder is also supported */
3249 memset(&clsid
, 0xcc, sizeof(clsid
));
3250 memset(&clsid2
, 0xab, sizeof(clsid2
));
3251 memset(&clsid3
, 0xcc, sizeof(clsid3
));
3252 hr
= pIUnknown_GetClassID((IUnknown
*)&testpersist2
, &clsid
);
3253 ok(hr
== 0x8fff2222, "got 0x%08x\n", hr
);
3254 ok(IsEqualCLSID(&clsid
, &clsid2
) || broken(IsEqualCLSID(&clsid
, &clsid3
)) /* win2k3 */,
3255 "got wrong clsid %s\n", wine_dbgstr_guid(&clsid
));
3263 hShlwapi
= GetModuleHandleA("shlwapi.dll");
3264 is_win2k_and_lower
= GetProcAddress(hShlwapi
, "StrChrNW") == 0;
3265 is_win9x
= GetProcAddress(hShlwapi
, (LPSTR
)99) == 0; /* StrCpyNXA */
3267 /* SHCreateStreamOnFileEx was introduced in shlwapi v6.0 */
3268 if(!GetProcAddress(hShlwapi
, "SHCreateStreamOnFileEx")){
3269 win_skip("Too old shlwapi version\n");
3275 argc
= winetest_get_mainargs(&argv
);
3280 sscanf(argv
[2], "%d", &procid
);
3281 sscanf(argv
[3], "%p", &hmem
);
3282 test_alloc_shared_remote(procid
, hmem
);
3286 hmlang
= LoadLibraryA("mlang.dll");
3287 pLcidToRfc1766A
= (void *)GetProcAddress(hmlang
, "LcidToRfc1766A");
3289 hshell32
= LoadLibraryA("shell32.dll");
3290 pSHGetDesktopFolder
= (void *)GetProcAddress(hshell32
, "SHGetDesktopFolder");
3292 test_GetAcceptLanguagesA();
3293 test_SHSearchMapInt();
3294 test_alloc_shared(argc
, argv
);
3296 test_GetShellSecurityDescriptor();
3297 test_SHPackDispParams();
3298 test_IConnectionPoint();
3299 test_SHPropertyBag_ReadLONG();
3300 test_SHSetWindowBits();
3301 test_SHFormatDateTimeA();
3302 test_SHFormatDateTimeW();
3303 test_SHGetObjectCompatFlags();
3304 test_IUnknown_QueryServiceExec();
3305 test_IUnknown_ProfferService();
3306 test_SHCreateWorkerWindowA();
3307 test_SHIShellFolder_EnumObjects();
3308 test_SHGetIniString();
3309 test_SHSetIniString();
3310 test_SHGetShellKey();
3311 test_SHSetParentHwnd();
3312 test_IUnknown_GetClassID();
3314 FreeLibrary(hshell32
);
3315 FreeLibrary(hmlang
);