mfplat: Read queue subscriber within the critical section.
[wine/zf.git] / dlls / shlwapi / tests / ordinal.c
blob919cac8563fdb815cfb814b4fd42155371809e1c
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 #include <stdio.h>
22 #define COBJMACROS
23 #define CONST_VTABLE
24 #include "wine/test.h"
25 #include "winbase.h"
26 #include "winerror.h"
27 #include "winuser.h"
28 #include "ole2.h"
29 #include "oaidl.h"
30 #include "ocidl.h"
31 #include "mlang.h"
32 #include "shlwapi.h"
33 #include "docobj.h"
34 #include "shobjidl.h"
35 #include "shlobj.h"
37 /* Function ptrs for ordinal calls */
38 static HMODULE hShlwapi;
40 static int (WINAPI *pSHSearchMapInt)(const int*,const int*,int,int);
41 static HRESULT (WINAPI *pGetAcceptLanguagesA)(LPSTR,LPDWORD);
43 static HANDLE (WINAPI *pSHAllocShared)(LPCVOID,DWORD,DWORD);
44 static LPVOID (WINAPI *pSHLockShared)(HANDLE,DWORD);
45 static BOOL (WINAPI *pSHUnlockShared)(LPVOID);
46 static BOOL (WINAPI *pSHFreeShared)(HANDLE,DWORD);
47 static HANDLE (WINAPI *pSHMapHandle)(HANDLE,DWORD,DWORD,DWORD,DWORD);
48 static HRESULT(WINAPIV *pSHPackDispParams)(DISPPARAMS*,VARIANTARG*,UINT,...);
49 static HRESULT(WINAPI *pIConnectionPoint_SimpleInvoke)(IConnectionPoint*,DISPID,DISPPARAMS*);
50 static HRESULT(WINAPI *pIConnectionPoint_InvokeWithCancel)(IConnectionPoint*,DISPID,DISPPARAMS*,DWORD,DWORD);
51 static HRESULT(WINAPI *pConnectToConnectionPoint)(IUnknown*,REFIID,BOOL,IUnknown*, LPDWORD,IConnectionPoint **);
52 static HRESULT(WINAPI *pSHPropertyBag_ReadLONG)(IPropertyBag *,LPCWSTR,LPLONG);
53 static LONG (WINAPI *pSHSetWindowBits)(HWND, INT, UINT, UINT);
54 static INT (WINAPI *pSHFormatDateTimeA)(const FILETIME UNALIGNED*, DWORD*, LPSTR, UINT);
55 static INT (WINAPI *pSHFormatDateTimeW)(const FILETIME UNALIGNED*, DWORD*, LPWSTR, UINT);
56 static DWORD (WINAPI *pSHGetObjectCompatFlags)(IUnknown*, const CLSID*);
57 static BOOL (WINAPI *pGUIDFromStringA)(LPSTR, CLSID *);
58 static HRESULT (WINAPI *pIUnknown_QueryServiceExec)(IUnknown*, REFIID, const GUID*, DWORD, DWORD, VARIANT*, VARIANT*);
59 static HRESULT (WINAPI *pIUnknown_ProfferService)(IUnknown*, REFGUID, IServiceProvider*, DWORD*);
60 static HWND (WINAPI *pSHCreateWorkerWindowA)(LONG, HWND, DWORD, DWORD, HMENU, LONG_PTR);
61 static HRESULT (WINAPI *pSHIShellFolder_EnumObjects)(LPSHELLFOLDER, HWND, SHCONTF, IEnumIDList**);
62 static DWORD (WINAPI *pSHGetIniStringW)(LPCWSTR, LPCWSTR, LPWSTR, DWORD, LPCWSTR);
63 static BOOL (WINAPI *pSHSetIniStringW)(LPCWSTR, LPCWSTR, LPCWSTR, LPCWSTR);
64 static HKEY (WINAPI *pSHGetShellKey)(DWORD, LPCWSTR, BOOL);
65 static HRESULT (WINAPI *pSKGetValueW)(DWORD, LPCWSTR, LPCWSTR, DWORD*, void*, DWORD*);
66 static HRESULT (WINAPI *pSKSetValueW)(DWORD, LPCWSTR, LPCWSTR, DWORD, void*, DWORD);
67 static HRESULT (WINAPI *pSKDeleteValueW)(DWORD, LPCWSTR, LPCWSTR);
68 static HRESULT (WINAPI *pSKAllocValueW)(DWORD, LPCWSTR, LPCWSTR, DWORD*, void**, DWORD*);
69 static HWND (WINAPI *pSHSetParentHwnd)(HWND, HWND);
70 static HRESULT (WINAPI *pIUnknown_GetClassID)(IUnknown*, CLSID*);
71 static HRESULT (WINAPI *pDllGetVersion)(DLLVERSIONINFO2*);
73 typedef struct SHELL_USER_SID {
74 SID_IDENTIFIER_AUTHORITY sidAuthority;
75 DWORD dwUserGroupID;
76 DWORD dwUserID;
77 } SHELL_USER_SID, *PSHELL_USER_SID;
78 typedef struct SHELL_USER_PERMISSION {
80 SHELL_USER_SID susID;
81 DWORD dwAccessType;
82 BOOL fInherit;
83 DWORD dwAccessMask;
84 DWORD dwInheritMask;
85 DWORD dwInheritAccessMask;
86 } SHELL_USER_PERMISSION, *PSHELL_USER_PERMISSION;
88 static SECURITY_DESCRIPTOR* (WINAPI *pGetShellSecurityDescriptor)(const SHELL_USER_PERMISSION**,int);
90 static const CHAR ie_international[] = {
91 'S','o','f','t','w','a','r','e','\\',
92 'M','i','c','r','o','s','o','f','t','\\',
93 'I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r','\\',
94 'I','n','t','e','r','n','a','t','i','o','n','a','l',0};
95 static const CHAR acceptlanguage[] = {
96 'A','c','c','e','p','t','L','a','n','g','u','a','g','e',0};
98 typedef struct {
99 int id;
100 const void *args[5];
101 } call_entry_t;
103 typedef struct {
104 call_entry_t *calls;
105 int count;
106 int alloc;
107 } call_trace_t;
109 static void init_call_trace(call_trace_t *ctrace)
111 ctrace->alloc = 10;
112 ctrace->count = 0;
113 ctrace->calls = HeapAlloc(GetProcessHeap(), 0, sizeof(call_entry_t) * ctrace->alloc);
116 static void free_call_trace(const call_trace_t *ctrace)
118 HeapFree(GetProcessHeap(), 0, ctrace->calls);
121 static void add_call(call_trace_t *ctrace, int id, const void *arg0,
122 const void *arg1, const void *arg2, const void *arg3, const void *arg4)
124 call_entry_t call;
126 call.id = id;
127 call.args[0] = arg0;
128 call.args[1] = arg1;
129 call.args[2] = arg2;
130 call.args[3] = arg3;
131 call.args[4] = arg4;
133 if (ctrace->count == ctrace->alloc)
135 ctrace->alloc *= 2;
136 ctrace->calls = HeapReAlloc(GetProcessHeap(),0, ctrace->calls, ctrace->alloc*sizeof(call_entry_t));
139 ctrace->calls[ctrace->count++] = call;
142 static void ok_trace_(call_trace_t *texpected, call_trace_t *tgot, int line)
144 if (texpected->count == tgot->count)
146 INT i;
147 /* compare */
148 for (i = 0; i < texpected->count; i++)
150 call_entry_t *expected = &texpected->calls[i];
151 call_entry_t *got = &tgot->calls[i];
152 INT j;
154 ok_(__FILE__, line)(expected->id == got->id, "got different ids %d: %d, %d\n", i+1, expected->id, got->id);
156 for (j = 0; j < 5; j++)
158 ok_(__FILE__, line)(expected->args[j] == got->args[j], "got different args[%d] for %d: %p, %p\n", j, i+1,
159 expected->args[j], got->args[j]);
163 else
164 ok_(__FILE__, line)(0, "traces length mismatch\n");
167 #define ok_trace(a, b) ok_trace_(a, b, __LINE__)
169 /* trace of actually made calls */
170 static call_trace_t trace_got;
172 static void test_GetAcceptLanguagesA(void)
174 static LPCSTR table[] = {"de,en-gb;q=0.7,en;q=0.3",
175 "de,en;q=0.3,en-gb;q=0.7", /* sorting is ignored */
176 "winetest", /* content is ignored */
177 "de-de,de;q=0.5",
178 "de",
179 NULL};
181 DWORD exactsize;
182 char original[512];
183 char language[32];
184 char buffer[64];
185 HKEY hroot = NULL;
186 LONG res_query = ERROR_SUCCESS;
187 LONG lres;
188 HRESULT hr;
189 DWORD maxlen = sizeof(buffer) - 2;
190 DWORD len;
191 LCID lcid;
192 LPCSTR entry;
193 INT i = 0;
195 lcid = GetUserDefaultLCID();
197 /* Get the original Value */
198 lres = RegOpenKeyA(HKEY_CURRENT_USER, ie_international, &hroot);
199 if (lres) {
200 skip("RegOpenKey(%s) failed: %d\n", ie_international, lres);
201 return;
203 len = sizeof(original);
204 original[0] = 0;
205 res_query = RegQueryValueExA(hroot, acceptlanguage, 0, NULL, (PBYTE)original, &len);
207 RegDeleteValueA(hroot, acceptlanguage);
209 /* Some windows versions use "lang-COUNTRY" as default */
210 memset(language, 0, sizeof(language));
211 len = GetLocaleInfoA(lcid, LOCALE_SISO639LANGNAME, language, sizeof(language));
213 if (len) {
214 lstrcatA(language, "-");
215 memset(buffer, 0, sizeof(buffer));
216 len = GetLocaleInfoA(lcid, LOCALE_SISO3166CTRYNAME, buffer, sizeof(buffer) - len - 1);
217 lstrcatA(language, buffer);
219 else
221 /* LOCALE_SNAME has additional parts in some languages. Try only as last chance */
222 memset(language, 0, sizeof(language));
223 len = GetLocaleInfoA(lcid, LOCALE_SNAME, language, sizeof(language));
226 /* get the default value */
227 len = maxlen;
228 memset(buffer, '#', maxlen);
229 buffer[maxlen] = 0;
230 hr = pGetAcceptLanguagesA( buffer, &len);
232 if (hr != S_OK) {
233 win_skip("GetAcceptLanguagesA failed with 0x%x\n", hr);
234 goto restore_original;
237 if (lstrcmpA(buffer, language)) {
238 /* some windows versions use "lang" or "lang-country" as default */
239 language[0] = 0;
240 hr = LcidToRfc1766A(lcid, language, sizeof(language));
241 ok(hr == S_OK, "LcidToRfc1766A returned 0x%x and %s\n", hr, language);
244 ok(!lstrcmpA(buffer, language),
245 "have '%s' (searching for '%s')\n", language, buffer);
247 if (lstrcmpA(buffer, language)) {
248 win_skip("no more ideas, how to build the default language '%s'\n", buffer);
249 goto restore_original;
252 trace("detected default: %s\n", language);
253 while ((entry = table[i])) {
255 exactsize = lstrlenA(entry);
257 lres = RegSetValueExA(hroot, acceptlanguage, 0, REG_SZ, (const BYTE *) entry, exactsize + 1);
258 ok(!lres, "got %d for RegSetValueExA: %s\n", lres, entry);
260 /* len includes space for the terminating 0 before vista/w2k8 */
261 len = exactsize + 2;
262 memset(buffer, '#', maxlen);
263 buffer[maxlen] = 0;
264 hr = pGetAcceptLanguagesA( buffer, &len);
265 ok(((hr == E_INVALIDARG) && (len == 0)) ||
266 (SUCCEEDED(hr) &&
267 ((len == exactsize) || (len == exactsize+1)) &&
268 !lstrcmpA(buffer, entry)),
269 "+2_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
271 len = exactsize + 1;
272 memset(buffer, '#', maxlen);
273 buffer[maxlen] = 0;
274 hr = pGetAcceptLanguagesA( buffer, &len);
275 ok(((hr == E_INVALIDARG) && (len == 0)) ||
276 (SUCCEEDED(hr) &&
277 ((len == exactsize) || (len == exactsize+1)) &&
278 !lstrcmpA(buffer, entry)),
279 "+1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
281 len = exactsize;
282 memset(buffer, '#', maxlen);
283 buffer[maxlen] = 0;
284 hr = pGetAcceptLanguagesA( buffer, &len);
286 /* There is no space for the string in the registry.
287 When the buffer is large enough, the default language is returned
289 When the buffer is too small for that fallback, win7_32 and w2k8_64
290 fail with E_NOT_SUFFICIENT_BUFFER, win8 fails with HRESULT_FROM_WIN32(ERROR_MORE_DATA),
291 other versions succeed and return a partial result while older os succeed
292 and overflow the buffer */
294 ok(((hr == E_INVALIDARG) && (len == 0)) ||
295 (((hr == S_OK) && !lstrcmpA(buffer, language) && (len == lstrlenA(language))) ||
296 ((hr == S_OK) && !memcmp(buffer, language, len)) ||
297 ((hr == E_NOT_SUFFICIENT_BUFFER) && !len) ||
298 ((hr == __HRESULT_FROM_WIN32(ERROR_MORE_DATA)) && len == exactsize)),
299 "==_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
301 if (exactsize > 1) {
302 len = exactsize - 1;
303 memset(buffer, '#', maxlen);
304 buffer[maxlen] = 0;
305 hr = pGetAcceptLanguagesA( buffer, &len);
306 ok(((hr == E_INVALIDARG) && (len == 0)) ||
307 (((hr == S_OK) && !lstrcmpA(buffer, language) && (len == lstrlenA(language))) ||
308 ((hr == S_OK) && !memcmp(buffer, language, len)) ||
309 ((hr == E_NOT_SUFFICIENT_BUFFER) && !len) ||
310 ((hr == __HRESULT_FROM_WIN32(ERROR_MORE_DATA)) && len == exactsize - 1)),
311 "-1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
314 len = 1;
315 memset(buffer, '#', maxlen);
316 buffer[maxlen] = 0;
317 hr = pGetAcceptLanguagesA( buffer, &len);
318 ok(((hr == E_INVALIDARG) && (len == 0)) ||
319 (((hr == S_OK) && !lstrcmpA(buffer, language) && (len == lstrlenA(language))) ||
320 ((hr == S_OK) && !memcmp(buffer, language, len)) ||
321 ((hr == E_NOT_SUFFICIENT_BUFFER) && !len) ||
322 ((hr == __HRESULT_FROM_WIN32(ERROR_MORE_DATA)) && len == 1)),
323 "=1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
325 len = maxlen;
326 hr = pGetAcceptLanguagesA( NULL, &len);
328 /* w2k3 and below: E_FAIL and untouched len,
329 since w2k8: S_OK and needed size (excluding 0), win8 S_OK and size including 0. */
330 ok( ((hr == S_OK) && ((len == exactsize) || (len == exactsize + 1))) ||
331 ((hr == E_FAIL) && (len == maxlen)),
332 "NULL,max #%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
334 i++;
337 /* without a value in the registry, a default language is returned */
338 RegDeleteValueA(hroot, acceptlanguage);
340 len = maxlen;
341 memset(buffer, '#', maxlen);
342 buffer[maxlen] = 0;
343 hr = pGetAcceptLanguagesA( buffer, &len);
344 ok( ((hr == S_OK) && (len == lstrlenA(language))),
345 "max: got 0x%x with %d and %s (expected S_OK with %d and '%s'\n",
346 hr, len, buffer, lstrlenA(language), language);
348 len = 2;
349 memset(buffer, '#', maxlen);
350 buffer[maxlen] = 0;
351 hr = pGetAcceptLanguagesA( buffer, &len);
352 ok( (((hr == S_OK) || (hr == E_INVALIDARG)) && !memcmp(buffer, language, len)) ||
353 ((hr == E_NOT_SUFFICIENT_BUFFER) && !len) ||
354 ((hr == __HRESULT_FROM_WIN32(ERROR_CANNOT_COPY)) && !len),
355 "=2: got 0x%x with %d and %s\n", hr, len, buffer);
357 len = 1;
358 memset(buffer, '#', maxlen);
359 buffer[maxlen] = 0;
360 hr = pGetAcceptLanguagesA( buffer, &len);
361 /* When the buffer is too small, win7_32 and w2k8_64 and above fail with
362 E_NOT_SUFFICIENT_BUFFER, win8 ERROR_CANNOT_COPY,
363 other versions succeed and return a partial 0 terminated result while other versions
364 fail with E_INVALIDARG and return a partial unterminated result */
365 ok( (((hr == S_OK) || (hr == E_INVALIDARG)) && !memcmp(buffer, language, len)) ||
366 ((hr == E_NOT_SUFFICIENT_BUFFER) && !len) ||
367 ((hr == __HRESULT_FROM_WIN32(ERROR_CANNOT_COPY)) && !len),
368 "=1: got 0x%x with %d and %s\n", hr, len, buffer);
370 len = 0;
371 memset(buffer, '#', maxlen);
372 buffer[maxlen] = 0;
373 hr = pGetAcceptLanguagesA( buffer, &len);
374 /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG, win8 ERROR_CANNOT_COPY */
375 ok((hr == E_FAIL) || (hr == E_INVALIDARG) || (hr == __HRESULT_FROM_WIN32(ERROR_CANNOT_COPY)),
376 "got 0x%x\n", hr);
378 memset(buffer, '#', maxlen);
379 buffer[maxlen] = 0;
380 hr = pGetAcceptLanguagesA( buffer, NULL);
381 /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG */
382 ok((hr == E_FAIL) || (hr == E_INVALIDARG),
383 "got 0x%x (expected E_FAIL or E_INVALIDARG)\n", hr);
386 hr = pGetAcceptLanguagesA( NULL, NULL);
387 /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG */
388 ok((hr == E_FAIL) || (hr == E_INVALIDARG),
389 "got 0x%x (expected E_FAIL or E_INVALIDARG)\n", hr);
391 restore_original:
392 if (!res_query) {
393 len = lstrlenA(original);
394 lres = RegSetValueExA(hroot, acceptlanguage, 0, REG_SZ, (const BYTE *) original, len ? len + 1: 0);
395 ok(!lres, "RegSetValueEx(%s) failed: %d\n", original, lres);
397 else
399 RegDeleteValueA(hroot, acceptlanguage);
401 RegCloseKey(hroot);
404 static void test_SHSearchMapInt(void)
406 int keys[8], values[8];
407 int i = 0;
409 if (!pSHSearchMapInt)
410 return;
412 memset(keys, 0, sizeof(keys));
413 memset(values, 0, sizeof(values));
414 keys[0] = 99; values[0] = 101;
416 /* NULL key/value lists crash native, so skip testing them */
418 /* 1 element */
419 i = pSHSearchMapInt(keys, values, 1, keys[0]);
420 ok(i == values[0], "Len 1, expected %d, got %d\n", values[0], i);
422 /* Key doesn't exist */
423 i = pSHSearchMapInt(keys, values, 1, 100);
424 ok(i == -1, "Len 1 - bad key, expected -1, got %d\n", i);
426 /* Len = 0 => not found */
427 i = pSHSearchMapInt(keys, values, 0, keys[0]);
428 ok(i == -1, "Len 1 - passed len 0, expected -1, got %d\n", i);
430 /* 2 elements, len = 1 */
431 keys[1] = 98; values[1] = 102;
432 i = pSHSearchMapInt(keys, values, 1, keys[1]);
433 ok(i == -1, "Len 1 - array len 2, expected -1, got %d\n", i);
435 /* 2 elements, len = 2 */
436 i = pSHSearchMapInt(keys, values, 2, keys[1]);
437 ok(i == values[1], "Len 2, expected %d, got %d\n", values[1], i);
439 /* Searches forward */
440 keys[2] = 99; values[2] = 103;
441 i = pSHSearchMapInt(keys, values, 3, keys[0]);
442 ok(i == values[0], "Len 3, expected %d, got %d\n", values[0], i);
445 struct shared_struct
447 DWORD value;
448 HANDLE handle;
451 static void test_alloc_shared(int argc, char **argv)
453 char cmdline[MAX_PATH];
454 PROCESS_INFORMATION pi;
455 STARTUPINFOA si = { 0 };
456 DWORD procid;
457 HANDLE hmem, hmem2 = 0;
458 struct shared_struct val, *p;
459 BOOL ret;
461 procid=GetCurrentProcessId();
462 hmem=pSHAllocShared(NULL,10,procid);
463 ok(hmem!=NULL,"SHAllocShared(NULL...) failed: %u\n", GetLastError());
464 ret = pSHFreeShared(hmem, procid);
465 ok( ret, "SHFreeShared failed: %u\n", GetLastError());
467 val.value = 0x12345678;
468 val.handle = 0;
469 hmem = pSHAllocShared(&val, sizeof(val), procid);
470 ok(hmem!=NULL,"SHAllocShared(NULL...) failed: %u\n", GetLastError());
472 p=pSHLockShared(hmem,procid);
473 ok(p!=NULL,"SHLockShared failed: %u\n", GetLastError());
474 if (p!=NULL)
475 ok(p->value == 0x12345678, "Wrong value in shared memory: %d instead of %d\n", p->value, 0x12345678);
476 ret = pSHUnlockShared(p);
477 ok( ret, "SHUnlockShared failed: %u\n", GetLastError());
479 sprintf(cmdline, "%s %s %d %p", argv[0], argv[1], procid, hmem);
480 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
481 ok(ret, "could not create child process error: %u\n", GetLastError());
482 if (ret)
484 wait_child_process(pi.hProcess);
485 CloseHandle(pi.hThread);
486 CloseHandle(pi.hProcess);
488 p = pSHLockShared(hmem, procid);
489 ok(p != NULL,"SHLockShared failed: %u\n", GetLastError());
490 if (p != NULL && p->value != 0x12345678)
492 ok(p->value == 0x12345679, "Wrong value in shared memory: %d instead of %d\n", p->value, 0x12345679);
493 hmem2 = p->handle;
494 ok(hmem2 != NULL, "Expected handle in shared memory\n");
496 ret = pSHUnlockShared(p);
497 ok(ret, "SHUnlockShared failed: %u\n", GetLastError());
500 ret = pSHFreeShared(hmem, procid);
501 ok( ret, "SHFreeShared failed: %u\n", GetLastError());
503 if (hmem2)
505 p = pSHLockShared(hmem2, procid);
506 ok(p != NULL,"SHLockShared failed: %u\n", GetLastError());
507 if (p != NULL)
508 ok(p->value == 0xDEADBEEF, "Wrong value in shared memory: %d instead of %d\n", p->value, 0xDEADBEEF);
509 ret = pSHUnlockShared(p);
510 ok(ret, "SHUnlockShared failed: %u\n", GetLastError());
512 ret = pSHFreeShared(hmem2, procid);
513 ok(ret, "SHFreeShared failed: %u\n", GetLastError());
516 SetLastError(0xdeadbeef);
517 ret = pSHFreeShared(NULL, procid);
518 ok(ret, "SHFreeShared failed: %u\n", GetLastError());
519 ok(GetLastError() == 0xdeadbeef, "last error should not have changed, got %u\n", GetLastError());
522 static void test_alloc_shared_remote(DWORD procid, HANDLE hmem)
524 struct shared_struct val, *p;
525 HANDLE hmem2;
526 BOOL ret;
528 /* test directly accessing shared memory of a remote process */
529 p = pSHLockShared(hmem, procid);
530 ok(p != NULL || broken(p == NULL) /* Windows 7/8 */, "SHLockShared failed: %u\n", GetLastError());
531 if (p == NULL)
533 win_skip("Subprocess failed to modify shared memory, skipping test\n");
534 return;
537 ok(p->value == 0x12345678, "Wrong value in shared memory: %d instead of %d\n", p->value, 0x12345678);
538 p->value++;
540 val.value = 0xDEADBEEF;
541 val.handle = 0;
542 p->handle = pSHAllocShared(&val, sizeof(val), procid);
543 ok(p->handle != NULL, "SHAllocShared failed: %u\n", GetLastError());
545 ret = pSHUnlockShared(p);
546 ok(ret, "SHUnlockShared failed: %u\n", GetLastError());
548 /* test SHMapHandle */
549 SetLastError(0xdeadbeef);
550 hmem2 = pSHMapHandle(NULL, procid, GetCurrentProcessId(), 0, 0);
551 ok(hmem2 == NULL, "expected NULL, got new handle\n");
552 ok(GetLastError() == 0xdeadbeef, "last error should not have changed, got %u\n", GetLastError());
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());
560 if (hmem2 == NULL)
562 win_skip("Subprocess failed to map shared memory, skipping test\n");
563 return;
566 p = pSHLockShared(hmem2, GetCurrentProcessId());
567 ok(p != NULL, "SHLockShared failed: %u\n", GetLastError());
569 if (p != NULL)
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)
581 typedef struct
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 */
589 } FDSA_info;
591 BOOL (WINAPI *pFDSA_Initialize)(DWORD block_size, DWORD inc, FDSA_info *info, void *mem,
592 DWORD init_blocks);
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);
597 FDSA_info info;
598 int block_size = 10, init_blocks = 4, inc = 2;
599 DWORD ret;
600 char *mem;
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);
679 static void test_GetShellSecurityDescriptor(void)
681 static const SHELL_USER_PERMISSION supCurrentUserFull = {
682 { {SECURITY_NULL_SID_AUTHORITY}, 0, 0 },
683 ACCESS_ALLOWED_ACE_TYPE, FALSE,
684 GENERIC_ALL, 0, 0 };
685 #define MY_INHERITANCE 0xBE /* invalid value to proof behavior */
686 static const SHELL_USER_PERMISSION supEveryoneDenied = {
687 { {SECURITY_WORLD_SID_AUTHORITY}, SECURITY_WORLD_RID, 0 },
688 ACCESS_DENIED_ACE_TYPE, TRUE,
689 GENERIC_WRITE, MY_INHERITANCE | 0xDEADBA00, GENERIC_READ };
690 const SHELL_USER_PERMISSION* rgsup[2] = {
691 &supCurrentUserFull, &supEveryoneDenied,
693 SECURITY_DESCRIPTOR* psd;
695 if(!pGetShellSecurityDescriptor) /* vista and later */
697 win_skip("GetShellSecurityDescriptor not available\n");
698 return;
701 psd = pGetShellSecurityDescriptor(NULL, 2);
702 ok(psd==NULL, "GetShellSecurityDescriptor should fail\n");
703 psd = pGetShellSecurityDescriptor(rgsup, 0);
704 ok(psd==NULL, "GetShellSecurityDescriptor should fail, got %p\n", psd);
706 SetLastError(0xdeadbeef);
707 psd = pGetShellSecurityDescriptor(rgsup, 2);
708 ok(psd!=NULL, "GetShellSecurityDescriptor failed\n");
709 if (psd!=NULL)
711 BOOL bHasDacl = FALSE, bDefaulted, ret;
712 PACL pAcl;
713 DWORD dwRev;
714 SECURITY_DESCRIPTOR_CONTROL control;
716 ok(IsValidSecurityDescriptor(psd), "returned value is not valid SD\n");
718 ret = GetSecurityDescriptorControl(psd, &control, &dwRev);
719 ok(ret, "GetSecurityDescriptorControl failed with error %u\n", GetLastError());
720 ok(0 == (control & SE_SELF_RELATIVE), "SD should be absolute\n");
722 ret = GetSecurityDescriptorDacl(psd, &bHasDacl, &pAcl, &bDefaulted);
723 ok(ret, "GetSecurityDescriptorDacl failed with error %u\n", GetLastError());
725 ok(bHasDacl, "SD has no DACL\n");
726 if (bHasDacl)
728 ok(!bDefaulted, "DACL should not be defaulted\n");
730 ok(pAcl != NULL, "NULL DACL!\n");
731 if (pAcl != NULL)
733 ACL_SIZE_INFORMATION asiSize;
735 ok(IsValidAcl(pAcl), "DACL is not valid\n");
737 ret = GetAclInformation(pAcl, &asiSize, sizeof(asiSize), AclSizeInformation);
738 ok(ret, "GetAclInformation failed with error %u\n", GetLastError());
740 ok(asiSize.AceCount == 3, "Incorrect number of ACEs: %d entries\n", asiSize.AceCount);
741 if (asiSize.AceCount == 3)
743 ACCESS_ALLOWED_ACE *paaa; /* will use for DENIED too */
745 ret = GetAce(pAcl, 0, (LPVOID*)&paaa);
746 ok(ret, "GetAce failed with error %u\n", GetLastError());
747 ok(paaa->Header.AceType == ACCESS_ALLOWED_ACE_TYPE,
748 "Invalid ACE type %d\n", paaa->Header.AceType);
749 ok(paaa->Header.AceFlags == 0, "Invalid ACE flags %x\n", paaa->Header.AceFlags);
750 ok(paaa->Mask == GENERIC_ALL, "Invalid ACE mask %x\n", paaa->Mask);
752 ret = GetAce(pAcl, 1, (LPVOID*)&paaa);
753 ok(ret, "GetAce failed with error %u\n", GetLastError());
754 ok(paaa->Header.AceType == ACCESS_DENIED_ACE_TYPE,
755 "Invalid ACE type %d\n", paaa->Header.AceType);
756 /* first one of two ACEs generated from inheritable entry - without inheritance */
757 ok(paaa->Header.AceFlags == 0, "Invalid ACE flags %x\n", paaa->Header.AceFlags);
758 ok(paaa->Mask == GENERIC_WRITE, "Invalid ACE mask %x\n", paaa->Mask);
760 ret = GetAce(pAcl, 2, (LPVOID*)&paaa);
761 ok(ret, "GetAce failed with error %u\n", GetLastError());
762 ok(paaa->Header.AceType == ACCESS_DENIED_ACE_TYPE,
763 "Invalid ACE type %d\n", paaa->Header.AceType);
764 /* second ACE - with inheritance */
765 ok(paaa->Header.AceFlags == MY_INHERITANCE,
766 "Invalid ACE flags %x\n", paaa->Header.AceFlags);
767 ok(paaa->Mask == GENERIC_READ, "Invalid ACE mask %x\n", paaa->Mask);
772 LocalFree(psd);
776 static void test_SHPackDispParams(void)
778 DISPPARAMS params;
779 VARIANT vars[10];
780 HRESULT hres;
782 memset(&params, 0xc0, sizeof(params));
783 memset(vars, 0xc0, sizeof(vars));
784 hres = pSHPackDispParams(&params, vars, 1, VT_I4, 0xdeadbeef);
785 ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres);
786 ok(params.cArgs == 1, "params.cArgs = %d\n", params.cArgs);
787 ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
788 ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
789 ok(params.rgvarg == vars, "params.rgvarg = %p\n", params.rgvarg);
790 ok(V_VT(vars) == VT_I4, "V_VT(var) = %d\n", V_VT(vars));
791 ok(V_I4(vars) == 0xdeadbeef, "failed %x\n", V_I4(vars));
793 memset(&params, 0xc0, sizeof(params));
794 hres = pSHPackDispParams(&params, NULL, 0, 0);
795 ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres);
796 ok(params.cArgs == 0, "params.cArgs = %d\n", params.cArgs);
797 ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
798 ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
799 ok(params.rgvarg == NULL, "params.rgvarg = %p\n", params.rgvarg);
801 memset(vars, 0xc0, sizeof(vars));
802 memset(&params, 0xc0, sizeof(params));
803 hres = pSHPackDispParams(&params, vars, 4, VT_BSTR, (void*)0xdeadbeef, VT_EMPTY, 10,
804 VT_I4, 100, VT_DISPATCH, (void*)0xdeadbeef);
805 ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres);
806 ok(params.cArgs == 4, "params.cArgs = %d\n", params.cArgs);
807 ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
808 ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
809 ok(params.rgvarg == vars, "params.rgvarg = %p\n", params.rgvarg);
810 ok(V_VT(vars) == VT_DISPATCH, "V_VT(vars[0]) = %x\n", V_VT(vars));
811 ok(V_I4(vars) == 0xdeadbeef, "V_I4(vars[0]) = %x\n", V_I4(vars));
812 ok(V_VT(vars+1) == VT_I4, "V_VT(vars[1]) = %d\n", V_VT(vars+1));
813 ok(V_I4(vars+1) == 100, "V_I4(vars[1]) = %x\n", V_I4(vars+1));
814 ok(V_VT(vars+2) == VT_I4, "V_VT(vars[2]) = %d\n", V_VT(vars+2));
815 ok(V_I4(vars+2) == 10, "V_I4(vars[2]) = %x\n", V_I4(vars+2));
816 ok(V_VT(vars+3) == VT_BSTR, "V_VT(vars[3]) = %d\n", V_VT(vars+3));
817 ok(V_BSTR(vars+3) == (void*)0xdeadbeef, "V_BSTR(vars[3]) = %p\n", V_BSTR(vars+3));
820 typedef struct _disp
822 IDispatch IDispatch_iface;
823 LONG refCount;
824 } Disp;
826 static inline Disp *impl_from_IDispatch(IDispatch *iface)
828 return CONTAINING_RECORD(iface, Disp, IDispatch_iface);
831 typedef struct _contain
833 IConnectionPointContainer IConnectionPointContainer_iface;
834 LONG refCount;
836 UINT ptCount;
837 IConnectionPoint **pt;
838 } Contain;
840 static inline Contain *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
842 return CONTAINING_RECORD(iface, Contain, IConnectionPointContainer_iface);
845 typedef struct _cntptn
847 IConnectionPoint IConnectionPoint_iface;
848 LONG refCount;
850 Contain *container;
851 GUID id;
852 UINT sinkCount;
853 IUnknown **sink;
854 } ConPt;
856 static inline ConPt *impl_from_IConnectionPoint(IConnectionPoint *iface)
858 return CONTAINING_RECORD(iface, ConPt, IConnectionPoint_iface);
861 typedef struct _enum
863 IEnumConnections IEnumConnections_iface;
864 LONG refCount;
866 UINT idx;
867 ConPt *pt;
868 } EnumCon;
870 static inline EnumCon *impl_from_IEnumConnections(IEnumConnections *iface)
872 return CONTAINING_RECORD(iface, EnumCon, IEnumConnections_iface);
875 typedef struct _enumpt
877 IEnumConnectionPoints IEnumConnectionPoints_iface;
878 LONG refCount;
880 int idx;
881 Contain *container;
882 } EnumPt;
884 static inline EnumPt *impl_from_IEnumConnectionPoints(IEnumConnectionPoints *iface)
886 return CONTAINING_RECORD(iface, EnumPt, IEnumConnectionPoints_iface);
890 static HRESULT WINAPI Disp_QueryInterface(
891 IDispatch* This,
892 REFIID riid,
893 void **ppvObject)
895 *ppvObject = NULL;
897 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDispatch))
899 *ppvObject = This;
902 if (*ppvObject)
904 IDispatch_AddRef(This);
905 return S_OK;
908 trace("no interface\n");
909 return E_NOINTERFACE;
912 static ULONG WINAPI Disp_AddRef(IDispatch* This)
914 Disp *iface = impl_from_IDispatch(This);
915 return InterlockedIncrement(&iface->refCount);
918 static ULONG WINAPI Disp_Release(IDispatch* This)
920 Disp *iface = impl_from_IDispatch(This);
921 ULONG ret;
923 ret = InterlockedDecrement(&iface->refCount);
924 if (ret == 0)
925 HeapFree(GetProcessHeap(),0,This);
926 return ret;
929 static HRESULT WINAPI Disp_GetTypeInfoCount(
930 IDispatch* This,
931 UINT *pctinfo)
933 return ERROR_SUCCESS;
936 static HRESULT WINAPI Disp_GetTypeInfo(
937 IDispatch* This,
938 UINT iTInfo,
939 LCID lcid,
940 ITypeInfo **ppTInfo)
942 return ERROR_SUCCESS;
945 static HRESULT WINAPI Disp_GetIDsOfNames(
946 IDispatch* This,
947 REFIID riid,
948 LPOLESTR *rgszNames,
949 UINT cNames,
950 LCID lcid,
951 DISPID *rgDispId)
953 return ERROR_SUCCESS;
956 static HRESULT WINAPI Disp_Invoke(
957 IDispatch* This,
958 DISPID dispIdMember,
959 REFIID riid,
960 LCID lcid,
961 WORD wFlags,
962 DISPPARAMS *pDispParams,
963 VARIANT *pVarResult,
964 EXCEPINFO *pExcepInfo,
965 UINT *puArgErr)
967 trace("%p %x %s %x %x %p %p %p %p\n", This, dispIdMember, wine_dbgstr_guid(riid), lcid, wFlags,
968 pDispParams, pVarResult, pExcepInfo, puArgErr);
970 ok(dispIdMember == 0xa0 || dispIdMember == 0xa1, "Unknown dispIdMember\n");
971 ok(pDispParams != NULL, "Invoked with NULL pDispParams\n");
972 ok(wFlags == DISPATCH_METHOD, "Wrong flags %x\n",wFlags);
973 ok(lcid == 0,"Wrong lcid %x\n",lcid);
974 if (dispIdMember == 0xa0)
976 ok(pDispParams->cArgs == 0, "params.cArgs = %d\n", pDispParams->cArgs);
977 ok(pDispParams->cNamedArgs == 0, "params.cNamedArgs = %d\n", pDispParams->cArgs);
978 ok(pDispParams->rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", pDispParams->rgdispidNamedArgs);
979 ok(pDispParams->rgvarg == NULL, "params.rgvarg = %p\n", pDispParams->rgvarg);
981 else if (dispIdMember == 0xa1)
983 ok(pDispParams->cArgs == 2, "params.cArgs = %d\n", pDispParams->cArgs);
984 ok(pDispParams->cNamedArgs == 0, "params.cNamedArgs = %d\n", pDispParams->cArgs);
985 ok(pDispParams->rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", pDispParams->rgdispidNamedArgs);
986 ok(V_VT(pDispParams->rgvarg) == VT_BSTR, "V_VT(var) = %d\n", V_VT(pDispParams->rgvarg));
987 ok(V_I4(pDispParams->rgvarg) == 0xdeadcafe , "failed %p\n", V_BSTR(pDispParams->rgvarg));
988 ok(V_VT(pDispParams->rgvarg+1) == VT_I4, "V_VT(var) = %d\n", V_VT(pDispParams->rgvarg+1));
989 ok(V_I4(pDispParams->rgvarg+1) == 0xdeadbeef, "failed %x\n", V_I4(pDispParams->rgvarg+1));
992 return ERROR_SUCCESS;
995 static const IDispatchVtbl disp_vtbl = {
996 Disp_QueryInterface,
997 Disp_AddRef,
998 Disp_Release,
1000 Disp_GetTypeInfoCount,
1001 Disp_GetTypeInfo,
1002 Disp_GetIDsOfNames,
1003 Disp_Invoke
1006 static HRESULT WINAPI Enum_QueryInterface(
1007 IEnumConnections* This,
1008 REFIID riid,
1009 void **ppvObject)
1011 *ppvObject = NULL;
1013 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumConnections))
1015 *ppvObject = This;
1018 if (*ppvObject)
1020 IEnumConnections_AddRef(This);
1021 return S_OK;
1024 trace("no interface\n");
1025 return E_NOINTERFACE;
1028 static ULONG WINAPI Enum_AddRef(IEnumConnections* This)
1030 EnumCon *iface = impl_from_IEnumConnections(This);
1031 return InterlockedIncrement(&iface->refCount);
1034 static ULONG WINAPI Enum_Release(IEnumConnections* This)
1036 EnumCon *iface = impl_from_IEnumConnections(This);
1037 ULONG ret;
1039 ret = InterlockedDecrement(&iface->refCount);
1040 if (ret == 0)
1041 HeapFree(GetProcessHeap(),0,This);
1042 return ret;
1045 static HRESULT WINAPI Enum_Next(
1046 IEnumConnections* This,
1047 ULONG cConnections,
1048 LPCONNECTDATA rgcd,
1049 ULONG *pcFetched)
1051 EnumCon *iface = impl_from_IEnumConnections(This);
1053 if (cConnections > 0 && iface->idx < iface->pt->sinkCount)
1055 rgcd->pUnk = iface->pt->sink[iface->idx];
1056 IUnknown_AddRef(iface->pt->sink[iface->idx]);
1057 rgcd->dwCookie=0xff;
1058 if (pcFetched)
1059 *pcFetched = 1;
1060 iface->idx++;
1061 return S_OK;
1064 return E_FAIL;
1067 static HRESULT WINAPI Enum_Skip(
1068 IEnumConnections* This,
1069 ULONG cConnections)
1071 return E_FAIL;
1074 static HRESULT WINAPI Enum_Reset(
1075 IEnumConnections* This)
1077 return E_FAIL;
1080 static HRESULT WINAPI Enum_Clone(
1081 IEnumConnections* This,
1082 IEnumConnections **ppEnum)
1084 return E_FAIL;
1087 static const IEnumConnectionsVtbl enum_vtbl = {
1089 Enum_QueryInterface,
1090 Enum_AddRef,
1091 Enum_Release,
1092 Enum_Next,
1093 Enum_Skip,
1094 Enum_Reset,
1095 Enum_Clone
1098 static HRESULT WINAPI ConPt_QueryInterface(
1099 IConnectionPoint* This,
1100 REFIID riid,
1101 void **ppvObject)
1103 *ppvObject = NULL;
1105 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IConnectionPoint))
1107 *ppvObject = This;
1110 if (*ppvObject)
1112 IConnectionPoint_AddRef(This);
1113 return S_OK;
1116 trace("no interface\n");
1117 return E_NOINTERFACE;
1120 static ULONG WINAPI ConPt_AddRef(
1121 IConnectionPoint* This)
1123 ConPt *iface = impl_from_IConnectionPoint(This);
1124 return InterlockedIncrement(&iface->refCount);
1127 static ULONG WINAPI ConPt_Release(
1128 IConnectionPoint* This)
1130 ConPt *iface = impl_from_IConnectionPoint(This);
1131 ULONG ret;
1133 ret = InterlockedDecrement(&iface->refCount);
1134 if (ret == 0)
1136 if (iface->sinkCount > 0)
1138 int i;
1139 for (i = 0; i < iface->sinkCount; i++)
1141 if (iface->sink[i])
1142 IUnknown_Release(iface->sink[i]);
1144 HeapFree(GetProcessHeap(),0,iface->sink);
1146 HeapFree(GetProcessHeap(),0,This);
1148 return ret;
1151 static HRESULT WINAPI ConPt_GetConnectionInterface(
1152 IConnectionPoint* This,
1153 IID *pIID)
1155 static int i = 0;
1156 ConPt *iface = impl_from_IConnectionPoint(This);
1157 if (i==0)
1159 i++;
1160 return E_FAIL;
1162 else
1163 memcpy(pIID,&iface->id,sizeof(GUID));
1164 return S_OK;
1167 static HRESULT WINAPI ConPt_GetConnectionPointContainer(
1168 IConnectionPoint* This,
1169 IConnectionPointContainer **ppCPC)
1171 ConPt *iface = impl_from_IConnectionPoint(This);
1173 *ppCPC = &iface->container->IConnectionPointContainer_iface;
1174 return S_OK;
1177 static HRESULT WINAPI ConPt_Advise(
1178 IConnectionPoint* This,
1179 IUnknown *pUnkSink,
1180 DWORD *pdwCookie)
1182 ConPt *iface = impl_from_IConnectionPoint(This);
1184 if (iface->sinkCount == 0)
1185 iface->sink = HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown*));
1186 else
1187 iface->sink = HeapReAlloc(GetProcessHeap(),0,iface->sink,sizeof(IUnknown*)*(iface->sinkCount+1));
1188 iface->sink[iface->sinkCount] = pUnkSink;
1189 IUnknown_AddRef(pUnkSink);
1190 iface->sinkCount++;
1191 *pdwCookie = iface->sinkCount;
1192 return S_OK;
1195 static HRESULT WINAPI ConPt_Unadvise(
1196 IConnectionPoint* This,
1197 DWORD dwCookie)
1199 ConPt *iface = impl_from_IConnectionPoint(This);
1201 if (dwCookie > iface->sinkCount)
1202 return E_FAIL;
1203 else
1205 IUnknown_Release(iface->sink[dwCookie-1]);
1206 iface->sink[dwCookie-1] = NULL;
1208 return S_OK;
1211 static HRESULT WINAPI ConPt_EnumConnections(
1212 IConnectionPoint* This,
1213 IEnumConnections **ppEnum)
1215 EnumCon *ec;
1217 ec = HeapAlloc(GetProcessHeap(),0,sizeof(EnumCon));
1218 ec->IEnumConnections_iface.lpVtbl = &enum_vtbl;
1219 ec->refCount = 1;
1220 ec->pt = impl_from_IConnectionPoint(This);
1221 ec->idx = 0;
1222 *ppEnum = &ec->IEnumConnections_iface;
1224 return S_OK;
1227 static const IConnectionPointVtbl point_vtbl = {
1228 ConPt_QueryInterface,
1229 ConPt_AddRef,
1230 ConPt_Release,
1232 ConPt_GetConnectionInterface,
1233 ConPt_GetConnectionPointContainer,
1234 ConPt_Advise,
1235 ConPt_Unadvise,
1236 ConPt_EnumConnections
1239 static HRESULT WINAPI EnumPt_QueryInterface(
1240 IEnumConnectionPoints* This,
1241 REFIID riid,
1242 void **ppvObject)
1244 *ppvObject = NULL;
1246 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumConnectionPoints))
1248 *ppvObject = This;
1251 if (*ppvObject)
1253 IEnumConnectionPoints_AddRef(This);
1254 return S_OK;
1257 trace("no interface\n");
1258 return E_NOINTERFACE;
1261 static ULONG WINAPI EnumPt_AddRef(IEnumConnectionPoints* This)
1263 EnumPt *iface = impl_from_IEnumConnectionPoints(This);
1264 return InterlockedIncrement(&iface->refCount);
1267 static ULONG WINAPI EnumPt_Release(IEnumConnectionPoints* This)
1269 EnumPt *iface = impl_from_IEnumConnectionPoints(This);
1270 ULONG ret;
1272 ret = InterlockedDecrement(&iface->refCount);
1273 if (ret == 0)
1274 HeapFree(GetProcessHeap(),0,This);
1275 return ret;
1278 static HRESULT WINAPI EnumPt_Next(
1279 IEnumConnectionPoints* This,
1280 ULONG cConnections,
1281 IConnectionPoint **rgcd,
1282 ULONG *pcFetched)
1284 EnumPt *iface = impl_from_IEnumConnectionPoints(This);
1286 if (cConnections > 0 && iface->idx < iface->container->ptCount)
1288 *rgcd = iface->container->pt[iface->idx];
1289 IConnectionPoint_AddRef(iface->container->pt[iface->idx]);
1290 if (pcFetched)
1291 *pcFetched = 1;
1292 iface->idx++;
1293 return S_OK;
1296 return E_FAIL;
1299 static HRESULT WINAPI EnumPt_Skip(
1300 IEnumConnectionPoints* This,
1301 ULONG cConnections)
1303 return E_FAIL;
1306 static HRESULT WINAPI EnumPt_Reset(
1307 IEnumConnectionPoints* This)
1309 return E_FAIL;
1312 static HRESULT WINAPI EnumPt_Clone(
1313 IEnumConnectionPoints* This,
1314 IEnumConnectionPoints **ppEnumPt)
1316 return E_FAIL;
1319 static const IEnumConnectionPointsVtbl enumpt_vtbl = {
1321 EnumPt_QueryInterface,
1322 EnumPt_AddRef,
1323 EnumPt_Release,
1324 EnumPt_Next,
1325 EnumPt_Skip,
1326 EnumPt_Reset,
1327 EnumPt_Clone
1330 static HRESULT WINAPI Contain_QueryInterface(
1331 IConnectionPointContainer* This,
1332 REFIID riid,
1333 void **ppvObject)
1335 *ppvObject = NULL;
1337 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IConnectionPointContainer))
1339 *ppvObject = This;
1342 if (*ppvObject)
1344 IConnectionPointContainer_AddRef(This);
1345 return S_OK;
1348 trace("no interface\n");
1349 return E_NOINTERFACE;
1352 static ULONG WINAPI Contain_AddRef(
1353 IConnectionPointContainer* This)
1355 Contain *iface = impl_from_IConnectionPointContainer(This);
1356 return InterlockedIncrement(&iface->refCount);
1359 static ULONG WINAPI Contain_Release(
1360 IConnectionPointContainer* This)
1362 Contain *iface = impl_from_IConnectionPointContainer(This);
1363 ULONG ret;
1365 ret = InterlockedDecrement(&iface->refCount);
1366 if (ret == 0)
1368 if (iface->ptCount > 0)
1370 int i;
1371 for (i = 0; i < iface->ptCount; i++)
1372 IConnectionPoint_Release(iface->pt[i]);
1373 HeapFree(GetProcessHeap(),0,iface->pt);
1375 HeapFree(GetProcessHeap(),0,This);
1377 return ret;
1380 static HRESULT WINAPI Contain_EnumConnectionPoints(
1381 IConnectionPointContainer* This,
1382 IEnumConnectionPoints **ppEnum)
1384 EnumPt *ec;
1386 ec = HeapAlloc(GetProcessHeap(),0,sizeof(EnumPt));
1387 ec->IEnumConnectionPoints_iface.lpVtbl = &enumpt_vtbl;
1388 ec->refCount = 1;
1389 ec->idx= 0;
1390 ec->container = impl_from_IConnectionPointContainer(This);
1391 *ppEnum = &ec->IEnumConnectionPoints_iface;
1393 return S_OK;
1396 static HRESULT WINAPI Contain_FindConnectionPoint(
1397 IConnectionPointContainer* This,
1398 REFIID riid,
1399 IConnectionPoint **ppCP)
1401 Contain *iface = impl_from_IConnectionPointContainer(This);
1402 ConPt *pt;
1404 if (!IsEqualIID(riid, &IID_NULL) || iface->ptCount ==0)
1406 pt = HeapAlloc(GetProcessHeap(),0,sizeof(ConPt));
1407 pt->IConnectionPoint_iface.lpVtbl = &point_vtbl;
1408 pt->refCount = 1;
1409 pt->sinkCount = 0;
1410 pt->sink = NULL;
1411 pt->container = iface;
1412 pt->id = IID_IDispatch;
1414 if (iface->ptCount == 0)
1415 iface->pt =HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown*));
1416 else
1417 iface->pt = HeapReAlloc(GetProcessHeap(),0,iface->pt,sizeof(IUnknown*)*(iface->ptCount+1));
1418 iface->pt[iface->ptCount] = &pt->IConnectionPoint_iface;
1419 iface->ptCount++;
1421 *ppCP = &pt->IConnectionPoint_iface;
1423 else
1425 *ppCP = iface->pt[0];
1426 IUnknown_AddRef((IUnknown*)*ppCP);
1429 return S_OK;
1432 static const IConnectionPointContainerVtbl contain_vtbl = {
1433 Contain_QueryInterface,
1434 Contain_AddRef,
1435 Contain_Release,
1437 Contain_EnumConnectionPoints,
1438 Contain_FindConnectionPoint
1441 static void test_IConnectionPoint(void)
1443 HRESULT rc;
1444 ULONG ref;
1445 IConnectionPoint *point;
1446 Contain *container;
1447 Disp *dispatch;
1448 DWORD cookie = 0xffffffff;
1449 DISPPARAMS params;
1450 VARIANT vars[10];
1452 container = HeapAlloc(GetProcessHeap(),0,sizeof(Contain));
1453 container->IConnectionPointContainer_iface.lpVtbl = &contain_vtbl;
1454 container->refCount = 1;
1455 container->ptCount = 0;
1456 container->pt = NULL;
1458 dispatch = HeapAlloc(GetProcessHeap(),0,sizeof(Disp));
1459 dispatch->IDispatch_iface.lpVtbl = &disp_vtbl;
1460 dispatch->refCount = 1;
1462 rc = pConnectToConnectionPoint((IUnknown*)dispatch, &IID_NULL, TRUE, (IUnknown*)container, &cookie, &point);
1463 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1464 ok(point != NULL, "returned ConnectionPoint is NULL\n");
1465 ok(cookie != 0xffffffff, "invalid cookie returned\n");
1467 rc = pIConnectionPoint_SimpleInvoke(point,0xa0,NULL);
1468 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1470 memset(&params, 0xc0, sizeof(params));
1471 memset(vars, 0xc0, sizeof(vars));
1472 rc = pSHPackDispParams(&params, vars, 2, VT_I4, 0xdeadbeef, VT_BSTR, 0xdeadcafe);
1473 ok(rc == S_OK, "SHPackDispParams failed: %08x\n", rc);
1475 rc = pIConnectionPoint_SimpleInvoke(point,0xa1,&params);
1476 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1478 rc = pConnectToConnectionPoint(NULL, &IID_NULL, FALSE, (IUnknown*)container, &cookie, NULL);
1479 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1481 /* MSDN says this should be required but it crashes on XP
1482 IUnknown_Release(point);
1484 ref = IUnknown_Release((IUnknown*)container);
1485 ok(ref == 0, "leftover IConnectionPointContainer reference %i\n",ref);
1486 ref = IUnknown_Release((IUnknown*)dispatch);
1487 ok(ref == 0, "leftover IDispatch reference %i\n",ref);
1490 typedef struct _propbag
1492 IPropertyBag IPropertyBag_iface;
1493 LONG refCount;
1495 } PropBag;
1497 static inline PropBag *impl_from_IPropertyBag(IPropertyBag *iface)
1499 return CONTAINING_RECORD(iface, PropBag, IPropertyBag_iface);
1503 static HRESULT WINAPI Prop_QueryInterface(
1504 IPropertyBag* This,
1505 REFIID riid,
1506 void **ppvObject)
1508 *ppvObject = NULL;
1510 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPropertyBag))
1512 *ppvObject = This;
1515 if (*ppvObject)
1517 IPropertyBag_AddRef(This);
1518 return S_OK;
1521 trace("no interface\n");
1522 return E_NOINTERFACE;
1525 static ULONG WINAPI Prop_AddRef(
1526 IPropertyBag* This)
1528 PropBag *iface = impl_from_IPropertyBag(This);
1529 return InterlockedIncrement(&iface->refCount);
1532 static ULONG WINAPI Prop_Release(
1533 IPropertyBag* This)
1535 PropBag *iface = impl_from_IPropertyBag(This);
1536 ULONG ret;
1538 ret = InterlockedDecrement(&iface->refCount);
1539 if (ret == 0)
1540 HeapFree(GetProcessHeap(),0,This);
1541 return ret;
1544 static HRESULT WINAPI Prop_Read(
1545 IPropertyBag* This,
1546 LPCOLESTR pszPropName,
1547 VARIANT *pVar,
1548 IErrorLog *pErrorLog)
1550 V_VT(pVar) = VT_BLOB|VT_BYREF;
1551 V_BYREF(pVar) = (LPVOID)0xdeadcafe;
1552 return S_OK;
1555 static HRESULT WINAPI Prop_Write(
1556 IPropertyBag* This,
1557 LPCOLESTR pszPropName,
1558 VARIANT *pVar)
1560 return S_OK;
1564 static const IPropertyBagVtbl prop_vtbl = {
1565 Prop_QueryInterface,
1566 Prop_AddRef,
1567 Prop_Release,
1569 Prop_Read,
1570 Prop_Write
1573 static void test_SHPropertyBag_ReadLONG(void)
1575 PropBag *pb;
1576 HRESULT rc;
1577 LONG out;
1578 static const WCHAR szName1[] = {'n','a','m','e','1',0};
1580 pb = HeapAlloc(GetProcessHeap(),0,sizeof(PropBag));
1581 pb->refCount = 1;
1582 pb->IPropertyBag_iface.lpVtbl = &prop_vtbl;
1584 out = 0xfeedface;
1585 rc = pSHPropertyBag_ReadLONG(NULL, szName1, &out);
1586 ok(rc == E_INVALIDARG || broken(rc == S_OK), "incorrect return %x\n",rc);
1587 ok(out == 0xfeedface, "value should not have changed\n");
1588 rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, NULL, &out);
1589 ok(rc == E_INVALIDARG || broken(rc == S_OK) || broken(rc == S_FALSE), "incorrect return %x\n",rc);
1590 ok(out == 0xfeedface, "value should not have changed\n");
1591 rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, szName1, NULL);
1592 ok(rc == E_INVALIDARG || broken(rc == S_OK) || broken(rc == S_FALSE), "incorrect return %x\n",rc);
1593 rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, szName1, &out);
1594 ok(rc == DISP_E_BADVARTYPE || broken(rc == S_OK) || broken(rc == S_FALSE), "incorrect return %x\n",rc);
1595 ok(out == 0xfeedface || broken(out == 0xfeedfa00), "value should not have changed %x\n",out);
1596 IUnknown_Release((IUnknown*)pb);
1599 static void test_SHSetWindowBits(void)
1601 HWND hwnd;
1602 DWORD style, styleold;
1603 WNDCLASSA clsA;
1605 clsA.style = 0;
1606 clsA.lpfnWndProc = DefWindowProcA;
1607 clsA.cbClsExtra = 0;
1608 clsA.cbWndExtra = 0;
1609 clsA.hInstance = GetModuleHandleA(NULL);
1610 clsA.hIcon = 0;
1611 clsA.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
1612 clsA.hbrBackground = NULL;
1613 clsA.lpszMenuName = NULL;
1614 clsA.lpszClassName = "Shlwapi test class";
1615 RegisterClassA(&clsA);
1617 hwnd = CreateWindowA("Shlwapi test class", "Test", WS_VISIBLE, 0, 0, 100, 100,
1618 NULL, NULL, GetModuleHandleA(NULL), 0);
1619 ok(IsWindow(hwnd), "failed to create window\n");
1621 /* null window */
1622 SetLastError(0xdeadbeef);
1623 style = pSHSetWindowBits(NULL, GWL_STYLE, 0, 0);
1624 ok(style == 0, "expected 0 retval, got %d\n", style);
1625 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE,
1626 "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
1628 /* zero mask, zero flags */
1629 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1630 style = pSHSetWindowBits(hwnd, GWL_STYLE, 0, 0);
1631 ok(styleold == style, "expected old style\n");
1632 ok(styleold == GetWindowLongA(hwnd, GWL_STYLE), "expected to keep old style\n");
1634 /* test mask */
1635 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1636 ok(styleold & WS_VISIBLE, "expected WS_VISIBLE\n");
1637 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1639 ok(style == styleold, "expected previous style, got %x\n", style);
1640 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1642 /* test mask, unset style bit used */
1643 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1644 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1645 ok(style == styleold, "expected previous style, got %x\n", style);
1646 ok(styleold == GetWindowLongA(hwnd, GWL_STYLE), "expected to keep old style\n");
1648 /* set back with flags */
1649 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1650 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, WS_VISIBLE);
1651 ok(style == styleold, "expected previous style, got %x\n", style);
1652 ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "expected updated style\n");
1654 /* reset and try to set without a mask */
1655 pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1656 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1657 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1658 style = pSHSetWindowBits(hwnd, GWL_STYLE, 0, WS_VISIBLE);
1659 ok(style == styleold, "expected previous style, got %x\n", style);
1660 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1662 DestroyWindow(hwnd);
1664 UnregisterClassA("Shlwapi test class", GetModuleHandleA(NULL));
1667 static void test_SHFormatDateTimeA(void)
1669 FILETIME UNALIGNED filetime;
1670 CHAR buff[100], buff2[100], buff3[100];
1671 SYSTEMTIME st;
1672 DWORD flags;
1673 INT ret;
1675 if (0)
1677 /* crashes on native */
1678 pSHFormatDateTimeA(NULL, NULL, NULL, 0);
1681 GetLocalTime(&st);
1682 SystemTimeToFileTime(&st, &filetime);
1683 /* SHFormatDateTime expects input as utc */
1684 LocalFileTimeToFileTime(&filetime, &filetime);
1686 /* no way to get required buffer length here */
1687 ret = pSHFormatDateTimeA(&filetime, NULL, NULL, 0);
1688 ok(ret == 0, "got %d\n", ret);
1690 SetLastError(0xdeadbeef);
1691 buff[0] = 'a'; buff[1] = 0;
1692 ret = pSHFormatDateTimeA(&filetime, NULL, buff, 0);
1693 ok(ret == 0, "got %d\n", ret);
1694 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1695 ok(buff[0] == 'a', "expected same string, got %s\n", buff);
1697 /* flags needs to have FDTF_NOAUTOREADINGORDER for these tests to succeed on Vista+ */
1699 /* all combinations documented as invalid succeeded */
1700 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTTIME | FDTF_LONGTIME;
1701 SetLastError(0xdeadbeef);
1702 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1703 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1704 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1706 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_LONGDATE;
1707 SetLastError(0xdeadbeef);
1708 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1709 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1710 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1712 flags = FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE;
1713 SetLastError(0xdeadbeef);
1714 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1715 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1716 ok(GetLastError() == 0xdeadbeef,
1717 "expected 0xdeadbeef, got %d\n", GetLastError());
1719 /* now check returned strings */
1720 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTTIME;
1721 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1722 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1723 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff2, sizeof(buff2));
1724 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1725 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1727 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGTIME;
1728 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1729 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1730 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2));
1731 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1732 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1734 /* both time flags */
1735 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGTIME | FDTF_SHORTTIME;
1736 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1737 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1738 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2));
1739 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1740 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1742 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE;
1743 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1744 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1745 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1746 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1747 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1749 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE;
1750 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1751 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1752 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1753 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1754 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1756 /* both date flags */
1757 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_SHORTDATE;
1758 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1759 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1760 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1761 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1762 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1764 /* various combinations of date/time flags */
1765 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_SHORTTIME;
1766 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1767 ok(ret == lstrlenA(buff)+1, "got %d, length %d\n", ret, lstrlenA(buff)+1);
1768 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3));
1769 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1770 ok(lstrcmpA(buff3, buff + lstrlenA(buff) - lstrlenA(buff3)) == 0,
1771 "expected (%s), got (%s) for time part\n",
1772 buff3, buff + lstrlenA(buff) - lstrlenA(buff3));
1773 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1774 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1775 buff[lstrlenA(buff2)] = '\0';
1776 ok(lstrcmpA(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1777 buff2, buff);
1779 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_LONGTIME;
1780 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1781 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1782 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3));
1783 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1784 ok(lstrcmpA(buff3, buff + lstrlenA(buff) - lstrlenA(buff3)) == 0,
1785 "expected (%s), got (%s) for time part\n",
1786 buff3, buff + lstrlenA(buff) - lstrlenA(buff3));
1787 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1788 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1789 buff[lstrlenA(buff2)] = '\0';
1790 ok(lstrcmpA(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1791 buff2, buff);
1793 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_SHORTTIME;
1794 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1795 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1796 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1797 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1798 strcat(buff2, " ");
1799 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3));
1800 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1801 strcat(buff2, buff3);
1802 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1804 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_LONGTIME;
1805 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1806 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1807 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1808 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1809 strcat(buff2, " ");
1810 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3));
1811 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1812 strcat(buff2, buff3);
1813 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1816 static void test_SHFormatDateTimeW(void)
1818 FILETIME UNALIGNED filetime;
1819 WCHAR buff[100], buff2[100], buff3[100], *p1, *p2;
1820 SYSTEMTIME st;
1821 DWORD flags;
1822 INT ret;
1823 static const WCHAR spaceW[] = {' ',0};
1824 #define UNICODE_LTR_MARK 0x200e
1825 #define UNICODE_RTL_MARK 0x200f
1827 if (0)
1829 /* crashes on native */
1830 pSHFormatDateTimeW(NULL, NULL, NULL, 0);
1833 GetLocalTime(&st);
1834 SystemTimeToFileTime(&st, &filetime);
1835 /* SHFormatDateTime expects input as utc */
1836 LocalFileTimeToFileTime(&filetime, &filetime);
1838 /* no way to get required buffer length here */
1839 SetLastError(0xdeadbeef);
1840 ret = pSHFormatDateTimeW(&filetime, NULL, NULL, 0);
1841 ok(ret == 0, "expected 0, got %d\n", ret);
1842 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1844 SetLastError(0xdeadbeef);
1845 buff[0] = 'a'; buff[1] = 0;
1846 ret = pSHFormatDateTimeW(&filetime, NULL, buff, 0);
1847 ok(ret == 0, "expected 0, got %d\n", ret);
1848 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1849 ok(buff[0] == 'a', "expected same string\n");
1851 /* all combinations documented as invalid succeeded */
1852 flags = FDTF_SHORTTIME | FDTF_LONGTIME;
1853 SetLastError(0xdeadbeef);
1854 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1855 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1856 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1857 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1859 flags = FDTF_SHORTDATE | FDTF_LONGDATE;
1860 SetLastError(0xdeadbeef);
1861 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1862 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1863 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1864 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1866 flags = FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE;
1867 SetLastError(0xdeadbeef);
1868 buff[0] = 0; /* NT4 doesn't clear the buffer on failure */
1869 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1870 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1871 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1872 ok(GetLastError() == 0xdeadbeef,
1873 "expected 0xdeadbeef, got %d\n", GetLastError());
1875 /* now check returned strings */
1876 flags = FDTF_SHORTTIME;
1877 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1878 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1879 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1880 SetLastError(0xdeadbeef);
1881 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff2, ARRAY_SIZE(buff2));
1882 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1883 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1885 flags = FDTF_LONGTIME;
1886 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1887 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1888 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1889 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, ARRAY_SIZE(buff2));
1890 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1891 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1893 /* both time flags */
1894 flags = FDTF_LONGTIME | FDTF_SHORTTIME;
1895 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1896 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1897 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1898 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, ARRAY_SIZE(buff2));
1899 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1900 ok(lstrcmpW(buff, buff2) == 0, "expected equal string\n");
1902 flags = FDTF_SHORTDATE;
1903 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1904 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1905 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1906 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, ARRAY_SIZE(buff2));
1907 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1908 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1910 flags = FDTF_LONGDATE;
1911 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1912 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1913 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1914 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, ARRAY_SIZE(buff2));
1915 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1916 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1918 /* both date flags */
1919 flags = FDTF_LONGDATE | FDTF_SHORTDATE;
1920 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1921 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1922 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1923 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, ARRAY_SIZE(buff2));
1924 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1925 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1927 /* various combinations of date/time flags */
1928 flags = FDTF_LONGDATE | FDTF_SHORTTIME;
1929 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1930 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1931 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1932 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, ARRAY_SIZE(buff3));
1933 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1934 ok(lstrcmpW(buff3, buff + lstrlenW(buff) - lstrlenW(buff3)) == 0,
1935 "expected (%s), got (%s) for time part\n",
1936 wine_dbgstr_w(buff3), wine_dbgstr_w(buff + lstrlenW(buff) - lstrlenW(buff3)));
1937 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, ARRAY_SIZE(buff2));
1938 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1939 p1 = buff;
1940 p2 = buff2;
1941 while (*p2 != '\0')
1943 while (*p1 == UNICODE_LTR_MARK || *p1 == UNICODE_RTL_MARK)
1944 p1++;
1945 while (*p2 == UNICODE_LTR_MARK || *p2 == UNICODE_RTL_MARK)
1946 p2++;
1947 p1++;
1948 p2++;
1950 *p1 = '\0';
1951 ok(lstrcmpW(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1952 wine_dbgstr_w(buff2), wine_dbgstr_w(buff));
1954 flags = FDTF_LONGDATE | FDTF_LONGTIME;
1955 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1956 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1957 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1958 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, ARRAY_SIZE(buff3));
1959 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1960 ok(lstrcmpW(buff3, buff + lstrlenW(buff) - lstrlenW(buff3)) == 0,
1961 "expected (%s), got (%s) for time part\n",
1962 wine_dbgstr_w(buff3), wine_dbgstr_w(buff + lstrlenW(buff) - lstrlenW(buff3)));
1963 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, ARRAY_SIZE(buff2));
1964 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1965 p1 = buff;
1966 p2 = buff2;
1967 while (*p2 != '\0')
1969 while (*p1 == UNICODE_LTR_MARK || *p1 == UNICODE_RTL_MARK)
1970 p1++;
1971 while (*p2 == UNICODE_LTR_MARK || *p2 == UNICODE_RTL_MARK)
1972 p2++;
1973 p1++;
1974 p2++;
1976 *p1 = '\0';
1977 ok(lstrcmpW(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1978 wine_dbgstr_w(buff2), wine_dbgstr_w(buff));
1980 flags = FDTF_SHORTDATE | FDTF_SHORTTIME;
1981 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1982 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1983 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1984 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, ARRAY_SIZE(buff2));
1985 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1986 lstrcatW(buff2, spaceW);
1987 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, ARRAY_SIZE(buff3));
1988 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1989 lstrcatW(buff2, buff3);
1990 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1992 flags = FDTF_SHORTDATE | FDTF_LONGTIME;
1993 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1994 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1995 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1996 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, ARRAY_SIZE(buff2));
1997 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1998 lstrcatW(buff2, spaceW);
1999 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, ARRAY_SIZE(buff3));
2000 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
2001 lstrcatW(buff2, buff3);
2002 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
2005 static void test_SHGetObjectCompatFlags(void)
2007 struct compat_value {
2008 CHAR nameA[30];
2009 DWORD value;
2012 struct compat_value values[] = {
2013 { "OTNEEDSSFCACHE", 0x1 },
2014 { "NO_WEBVIEW", 0x2 },
2015 { "UNBINDABLE", 0x4 },
2016 { "PINDLL", 0x8 },
2017 { "NEEDSFILESYSANCESTOR", 0x10 },
2018 { "NOTAFILESYSTEM", 0x20 },
2019 { "CTXMENU_NOVERBS", 0x40 },
2020 { "CTXMENU_LIMITEDQI", 0x80 },
2021 { "COCREATESHELLFOLDERONLY", 0x100 },
2022 { "NEEDSSTORAGEANCESTOR", 0x200 },
2023 { "NOLEGACYWEBVIEW", 0x400 },
2024 { "CTXMENU_XPQCMFLAGS", 0x1000 },
2025 { "NOIPROPERTYSTORE", 0x2000 }
2028 static const char compat_path[] = "Software\\Microsoft\\Windows\\CurrentVersion\\ShellCompatibility\\Objects";
2029 CHAR keyA[39]; /* {CLSID} */
2030 HKEY root;
2031 DWORD ret;
2032 int i;
2034 /* null args */
2035 ret = pSHGetObjectCompatFlags(NULL, NULL);
2036 ok(ret == 0, "got %d\n", ret);
2038 ret = RegOpenKeyA(HKEY_LOCAL_MACHINE, compat_path, &root);
2039 if (ret != ERROR_SUCCESS)
2041 skip("No compatibility class data found\n");
2042 return;
2045 for (i = 0; RegEnumKeyA(root, i, keyA, sizeof(keyA)) == ERROR_SUCCESS; i++)
2047 HKEY clsid_key;
2049 if (RegOpenKeyA(root, keyA, &clsid_key) == ERROR_SUCCESS)
2051 CHAR valueA[30];
2052 DWORD expected = 0, got, length = sizeof(valueA);
2053 CLSID clsid;
2054 int v;
2056 for (v = 0; RegEnumValueA(clsid_key, v, valueA, &length, NULL, NULL, NULL, NULL) == ERROR_SUCCESS; v++)
2058 int j;
2060 for (j = 0; j < ARRAY_SIZE(values); j++)
2061 if (lstrcmpA(values[j].nameA, valueA) == 0)
2063 expected |= values[j].value;
2064 break;
2067 length = sizeof(valueA);
2070 pGUIDFromStringA(keyA, &clsid);
2071 got = pSHGetObjectCompatFlags(NULL, &clsid);
2072 ok(got == expected, "got 0x%08x, expected 0x%08x. Key %s\n", got, expected, keyA);
2074 RegCloseKey(clsid_key);
2078 RegCloseKey(root);
2081 typedef struct {
2082 IOleCommandTarget IOleCommandTarget_iface;
2083 LONG ref;
2084 } IOleCommandTargetImpl;
2086 static inline IOleCommandTargetImpl *impl_from_IOleCommandTarget(IOleCommandTarget *iface)
2088 return CONTAINING_RECORD(iface, IOleCommandTargetImpl, IOleCommandTarget_iface);
2091 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl;
2093 static IOleCommandTarget* IOleCommandTargetImpl_Construct(void)
2095 IOleCommandTargetImpl *obj;
2097 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2098 obj->IOleCommandTarget_iface.lpVtbl = &IOleCommandTargetImpl_Vtbl;
2099 obj->ref = 1;
2101 return &obj->IOleCommandTarget_iface;
2104 static HRESULT WINAPI IOleCommandTargetImpl_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppvObj)
2106 IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface);
2108 if (IsEqualIID(riid, &IID_IUnknown) ||
2109 IsEqualIID(riid, &IID_IOleCommandTarget))
2111 *ppvObj = This;
2114 if(*ppvObj)
2116 IOleCommandTarget_AddRef(iface);
2117 return S_OK;
2120 return E_NOINTERFACE;
2123 static ULONG WINAPI IOleCommandTargetImpl_AddRef(IOleCommandTarget *iface)
2125 IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface);
2126 return InterlockedIncrement(&This->ref);
2129 static ULONG WINAPI IOleCommandTargetImpl_Release(IOleCommandTarget *iface)
2131 IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface);
2132 ULONG ref = InterlockedDecrement(&This->ref);
2134 if (!ref)
2136 HeapFree(GetProcessHeap(), 0, This);
2137 return 0;
2139 return ref;
2142 static HRESULT WINAPI IOleCommandTargetImpl_QueryStatus(
2143 IOleCommandTarget *iface, const GUID *group, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText)
2145 return E_NOTIMPL;
2148 static HRESULT WINAPI IOleCommandTargetImpl_Exec(
2149 IOleCommandTarget *iface,
2150 const GUID *CmdGroup,
2151 DWORD nCmdID,
2152 DWORD nCmdexecopt,
2153 VARIANT *pvaIn,
2154 VARIANT *pvaOut)
2156 add_call(&trace_got, 3, CmdGroup, (void*)(DWORD_PTR)nCmdID, (void*)(DWORD_PTR)nCmdexecopt, pvaIn, pvaOut);
2157 return S_OK;
2160 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl =
2162 IOleCommandTargetImpl_QueryInterface,
2163 IOleCommandTargetImpl_AddRef,
2164 IOleCommandTargetImpl_Release,
2165 IOleCommandTargetImpl_QueryStatus,
2166 IOleCommandTargetImpl_Exec
2169 typedef struct {
2170 IServiceProvider IServiceProvider_iface;
2171 LONG ref;
2172 } IServiceProviderImpl;
2174 static inline IServiceProviderImpl *impl_from_IServiceProvider(IServiceProvider *iface)
2176 return CONTAINING_RECORD(iface, IServiceProviderImpl, IServiceProvider_iface);
2179 typedef struct {
2180 IProfferService IProfferService_iface;
2181 LONG ref;
2182 } IProfferServiceImpl;
2184 static inline IProfferServiceImpl *impl_from_IProfferService(IProfferService *iface)
2186 return CONTAINING_RECORD(iface, IProfferServiceImpl, IProfferService_iface);
2190 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl;
2191 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl;
2193 static IServiceProvider* IServiceProviderImpl_Construct(void)
2195 IServiceProviderImpl *obj;
2197 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2198 obj->IServiceProvider_iface.lpVtbl = &IServiceProviderImpl_Vtbl;
2199 obj->ref = 1;
2201 return &obj->IServiceProvider_iface;
2204 static IProfferService* IProfferServiceImpl_Construct(void)
2206 IProfferServiceImpl *obj;
2208 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2209 obj->IProfferService_iface.lpVtbl = &IProfferServiceImpl_Vtbl;
2210 obj->ref = 1;
2212 return &obj->IProfferService_iface;
2215 static HRESULT WINAPI IServiceProviderImpl_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppvObj)
2217 IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
2219 if (IsEqualIID(riid, &IID_IUnknown) ||
2220 IsEqualIID(riid, &IID_IServiceProvider))
2222 *ppvObj = This;
2225 if(*ppvObj)
2227 IServiceProvider_AddRef(iface);
2228 /* native uses redefined IID_IServiceProvider symbol, so we can't compare pointers */
2229 if (IsEqualIID(riid, &IID_IServiceProvider))
2230 add_call(&trace_got, 1, iface, &IID_IServiceProvider, 0, 0, 0);
2231 return S_OK;
2234 return E_NOINTERFACE;
2237 static ULONG WINAPI IServiceProviderImpl_AddRef(IServiceProvider *iface)
2239 IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
2240 return InterlockedIncrement(&This->ref);
2243 static ULONG WINAPI IServiceProviderImpl_Release(IServiceProvider *iface)
2245 IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
2246 ULONG ref = InterlockedDecrement(&This->ref);
2248 if (!ref)
2250 HeapFree(GetProcessHeap(), 0, This);
2251 return 0;
2253 return ref;
2256 static HRESULT WINAPI IServiceProviderImpl_QueryService(
2257 IServiceProvider *iface, REFGUID service, REFIID riid, void **ppv)
2259 /* native uses redefined pointer for IID_IOleCommandTarget, not one from uuid.lib */
2260 if (IsEqualIID(riid, &IID_IOleCommandTarget))
2262 add_call(&trace_got, 2, iface, service, &IID_IOleCommandTarget, 0, 0);
2263 *ppv = IOleCommandTargetImpl_Construct();
2265 if (IsEqualIID(riid, &IID_IProfferService))
2267 if (IsEqualIID(service, &IID_IProfferService))
2268 add_call(&trace_got, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2269 *ppv = IProfferServiceImpl_Construct();
2271 return S_OK;
2274 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl =
2276 IServiceProviderImpl_QueryInterface,
2277 IServiceProviderImpl_AddRef,
2278 IServiceProviderImpl_Release,
2279 IServiceProviderImpl_QueryService
2282 static void test_IUnknown_QueryServiceExec(void)
2284 IServiceProvider *provider;
2285 static const GUID dummy_serviceid = { 0xdeadbeef };
2286 static const GUID dummy_groupid = { 0xbeefbeef };
2287 call_trace_t trace_expected;
2288 HRESULT hr;
2290 provider = IServiceProviderImpl_Construct();
2292 /* null source pointer */
2293 hr = pIUnknown_QueryServiceExec(NULL, &dummy_serviceid, &dummy_groupid, 0, 0, 0, 0);
2294 ok(hr == E_FAIL ||
2295 hr == E_NOTIMPL, /* win 8 */
2296 "got 0x%08x\n", hr);
2298 /* expected trace:
2299 IUnknown_QueryServiceExec( ptr1, serviceid, groupid, arg1, arg2, arg3, arg4);
2300 -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &prov );
2301 -> IServiceProvider_QueryService( prov, serviceid, &IID_IOleCommandTarget, &obj );
2302 -> IOleCommandTarget_Exec( obj, groupid, arg1, arg2, arg3, arg4 );
2304 init_call_trace(&trace_expected);
2306 add_call(&trace_expected, 1, provider, &IID_IServiceProvider, 0, 0, 0);
2307 add_call(&trace_expected, 2, provider, &dummy_serviceid, &IID_IOleCommandTarget, 0, 0);
2308 add_call(&trace_expected, 3, &dummy_groupid, (void*)0x1, (void*)0x2, (void*)0x3, (void*)0x4);
2310 init_call_trace(&trace_got);
2311 hr = pIUnknown_QueryServiceExec((IUnknown*)provider, &dummy_serviceid, &dummy_groupid, 0x1, 0x2, (void*)0x3, (void*)0x4);
2312 ok(hr == S_OK, "got 0x%08x\n", hr);
2314 ok_trace(&trace_expected, &trace_got);
2316 free_call_trace(&trace_expected);
2317 free_call_trace(&trace_got);
2319 IServiceProvider_Release(provider);
2323 static HRESULT WINAPI IProfferServiceImpl_QueryInterface(IProfferService *iface, REFIID riid, void **ppvObj)
2325 IProfferServiceImpl *This = impl_from_IProfferService(iface);
2327 if (IsEqualIID(riid, &IID_IUnknown) ||
2328 IsEqualIID(riid, &IID_IProfferService))
2330 *ppvObj = This;
2332 else if (IsEqualIID(riid, &IID_IServiceProvider))
2334 *ppvObj = IServiceProviderImpl_Construct();
2335 add_call(&trace_got, 1, iface, &IID_IServiceProvider, 0, 0, 0);
2336 return S_OK;
2339 if(*ppvObj)
2341 IProfferService_AddRef(iface);
2342 return S_OK;
2345 return E_NOINTERFACE;
2348 static ULONG WINAPI IProfferServiceImpl_AddRef(IProfferService *iface)
2350 IProfferServiceImpl *This = impl_from_IProfferService(iface);
2351 return InterlockedIncrement(&This->ref);
2354 static ULONG WINAPI IProfferServiceImpl_Release(IProfferService *iface)
2356 IProfferServiceImpl *This = impl_from_IProfferService(iface);
2357 ULONG ref = InterlockedDecrement(&This->ref);
2359 if (!ref)
2361 HeapFree(GetProcessHeap(), 0, This);
2362 return 0;
2364 return ref;
2367 static HRESULT WINAPI IProfferServiceImpl_ProfferService(IProfferService *iface,
2368 REFGUID service, IServiceProvider *pService, DWORD *pCookie)
2370 *pCookie = 0xdeadbeef;
2371 add_call(&trace_got, 3, service, pService, pCookie, 0, 0);
2372 return S_OK;
2375 static HRESULT WINAPI IProfferServiceImpl_RevokeService(IProfferService *iface, DWORD cookie)
2377 add_call(&trace_got, 4, (void*)(DWORD_PTR)cookie, 0, 0, 0, 0);
2378 return S_OK;
2381 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl =
2383 IProfferServiceImpl_QueryInterface,
2384 IProfferServiceImpl_AddRef,
2385 IProfferServiceImpl_Release,
2386 IProfferServiceImpl_ProfferService,
2387 IProfferServiceImpl_RevokeService
2390 static void test_IUnknown_ProfferService(void)
2392 IServiceProvider *provider;
2393 IProfferService *proff;
2394 static const GUID dummy_serviceid = { 0xdeadbeef };
2395 call_trace_t trace_expected;
2396 HRESULT hr;
2397 DWORD cookie;
2399 provider = IServiceProviderImpl_Construct();
2400 proff = IProfferServiceImpl_Construct();
2402 /* null source pointer */
2403 hr = pIUnknown_ProfferService(NULL, &dummy_serviceid, 0, 0);
2404 ok(hr == E_FAIL ||
2405 hr == E_NOTIMPL, /* win 8 */
2406 "got 0x%08x\n", hr);
2408 /* expected trace:
2409 IUnknown_ProfferService( ptr1, serviceid, arg1, arg2);
2410 -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &provider );
2411 -> IServiceProvider_QueryService( provider, &IID_IProfferService, &IID_IProfferService, &proffer );
2413 if (service pointer not null):
2414 -> IProfferService_ProfferService( proffer, serviceid, arg1, arg2 );
2415 else
2416 -> IProfferService_RevokeService( proffer, *arg2 );
2418 init_call_trace(&trace_expected);
2420 add_call(&trace_expected, 1, proff, &IID_IServiceProvider, 0, 0, 0);
2421 add_call(&trace_expected, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2422 add_call(&trace_expected, 3, &dummy_serviceid, provider, &cookie, 0, 0);
2424 init_call_trace(&trace_got);
2425 cookie = 0;
2426 hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, provider, &cookie);
2427 ok(hr == S_OK, "got 0x%08x\n", hr);
2428 ok(cookie == 0xdeadbeef, "got %x\n", cookie);
2430 ok_trace(&trace_expected, &trace_got);
2431 free_call_trace(&trace_got);
2432 free_call_trace(&trace_expected);
2434 /* same with ::Revoke path */
2435 init_call_trace(&trace_expected);
2437 add_call(&trace_expected, 1, proff, &IID_IServiceProvider, 0, 0, 0);
2438 add_call(&trace_expected, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2439 add_call(&trace_expected, 4, (void*)(DWORD_PTR)cookie, 0, 0, 0, 0);
2441 init_call_trace(&trace_got);
2442 ok(cookie != 0, "got %x\n", cookie);
2443 hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, 0, &cookie);
2444 ok(hr == S_OK, "got 0x%08x\n", hr);
2445 ok(cookie == 0, "got %x\n", cookie);
2446 ok_trace(&trace_expected, &trace_got);
2447 free_call_trace(&trace_got);
2448 free_call_trace(&trace_expected);
2450 IServiceProvider_Release(provider);
2451 IProfferService_Release(proff);
2454 static void test_SHCreateWorkerWindowA(void)
2456 WNDCLASSA cliA;
2457 char classA[20];
2458 HWND hwnd;
2459 LONG_PTR ret;
2460 BOOL res;
2462 hwnd = pSHCreateWorkerWindowA(0, NULL, 0, 0, 0, 0);
2463 ok(hwnd != 0, "expected window\n");
2465 GetClassNameA(hwnd, classA, 20);
2466 ok(lstrcmpA(classA, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA);
2468 ret = GetWindowLongPtrA(hwnd, 0);
2469 ok(ret == 0, "got %ld\n", ret);
2471 /* class info */
2472 memset(&cliA, 0, sizeof(cliA));
2473 res = GetClassInfoA(GetModuleHandleA("shlwapi.dll"), "WorkerA", &cliA);
2474 ok(res, "failed to get class info\n");
2475 ok(cliA.style == 0, "got 0x%08x\n", cliA.style);
2476 ok(cliA.cbClsExtra == 0, "got %d\n", cliA.cbClsExtra);
2477 ok(cliA.cbWndExtra == sizeof(LONG_PTR), "got %d\n", cliA.cbWndExtra);
2478 ok(cliA.lpszMenuName == 0, "got %s\n", cliA.lpszMenuName);
2480 DestroyWindow(hwnd);
2482 /* set extra bytes */
2483 hwnd = pSHCreateWorkerWindowA(0, NULL, 0, 0, 0, 0xdeadbeef);
2484 ok(hwnd != 0, "expected window\n");
2486 GetClassNameA(hwnd, classA, 20);
2487 ok(lstrcmpA(classA, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA);
2489 ret = GetWindowLongPtrA(hwnd, 0);
2490 ok(ret == 0xdeadbeef, "got %ld\n", ret);
2492 /* test exstyle */
2493 ret = GetWindowLongA(hwnd, GWL_EXSTYLE);
2494 ok(ret == WS_EX_WINDOWEDGE ||
2495 ret == (WS_EX_WINDOWEDGE|WS_EX_LAYOUTRTL) /* systems with RTL locale */, "0x%08lx\n", ret);
2497 DestroyWindow(hwnd);
2499 hwnd = pSHCreateWorkerWindowA(0, NULL, WS_EX_TOOLWINDOW, 0, 0, 0);
2500 ret = GetWindowLongA(hwnd, GWL_EXSTYLE);
2501 ok(ret == (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW) ||
2502 ret == (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW|WS_EX_LAYOUTRTL) /* systems with RTL locale */, "0x%08lx\n", ret);
2503 DestroyWindow(hwnd);
2506 static HRESULT WINAPI SF_QueryInterface(IShellFolder *iface,
2507 REFIID riid, void **ppv)
2509 /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */
2510 ok(!IsEqualGUID(&IID_IShellFolder, riid),
2511 "Unexpected QI for IShellFolder\n");
2512 return E_NOINTERFACE;
2515 static ULONG WINAPI SF_AddRef(IShellFolder *iface)
2517 return 2;
2520 static ULONG WINAPI SF_Release(IShellFolder *iface)
2522 return 1;
2525 static HRESULT WINAPI SF_ParseDisplayName(IShellFolder *iface,
2526 HWND owner, LPBC reserved, LPOLESTR displayName, ULONG *eaten,
2527 LPITEMIDLIST *idl, ULONG *attr)
2529 ok(0, "Didn't expect ParseDisplayName\n");
2530 return E_NOTIMPL;
2533 static HRESULT WINAPI SF_EnumObjects(IShellFolder *iface,
2534 HWND owner, SHCONTF flags, IEnumIDList **enm)
2536 *enm = (IEnumIDList*)0xcafebabe;
2537 return S_OK;
2540 static HRESULT WINAPI SF_BindToObject(IShellFolder *iface,
2541 LPCITEMIDLIST idl, LPBC reserved, REFIID riid, void **obj)
2543 ok(0, "Didn't expect BindToObject\n");
2544 return E_NOTIMPL;
2547 static HRESULT WINAPI SF_BindToStorage(IShellFolder *iface,
2548 LPCITEMIDLIST idl, LPBC reserved, REFIID riid, void **obj)
2550 ok(0, "Didn't expect BindToStorage\n");
2551 return E_NOTIMPL;
2554 static HRESULT WINAPI SF_CompareIDs(IShellFolder *iface,
2555 LPARAM lparam, LPCITEMIDLIST idl1, LPCITEMIDLIST idl2)
2557 ok(0, "Didn't expect CompareIDs\n");
2558 return E_NOTIMPL;
2561 static HRESULT WINAPI SF_CreateViewObject(IShellFolder *iface,
2562 HWND owner, REFIID riid, void **out)
2564 ok(0, "Didn't expect CreateViewObject\n");
2565 return E_NOTIMPL;
2568 static HRESULT WINAPI SF_GetAttributesOf(IShellFolder *iface,
2569 UINT cidl, LPCITEMIDLIST *idl, SFGAOF *inOut)
2571 ok(0, "Didn't expect GetAttributesOf\n");
2572 return E_NOTIMPL;
2575 static HRESULT WINAPI SF_GetUIObjectOf(IShellFolder *iface,
2576 HWND owner, UINT cidl, LPCITEMIDLIST *idls, REFIID riid, UINT *inOut,
2577 void **out)
2579 ok(0, "Didn't expect GetUIObjectOf\n");
2580 return E_NOTIMPL;
2583 static HRESULT WINAPI SF_GetDisplayNameOf(IShellFolder *iface,
2584 LPCITEMIDLIST idl, SHGDNF flags, STRRET *name)
2586 ok(0, "Didn't expect GetDisplayNameOf\n");
2587 return E_NOTIMPL;
2590 static HRESULT WINAPI SF_SetNameOf(IShellFolder *iface,
2591 HWND hwnd, LPCITEMIDLIST idl, LPCOLESTR name, SHGDNF flags,
2592 LPITEMIDLIST *idlOut)
2594 ok(0, "Didn't expect SetNameOf\n");
2595 return E_NOTIMPL;
2598 static IShellFolderVtbl ShellFolderVtbl = {
2599 SF_QueryInterface,
2600 SF_AddRef,
2601 SF_Release,
2602 SF_ParseDisplayName,
2603 SF_EnumObjects,
2604 SF_BindToObject,
2605 SF_BindToStorage,
2606 SF_CompareIDs,
2607 SF_CreateViewObject,
2608 SF_GetAttributesOf,
2609 SF_GetUIObjectOf,
2610 SF_GetDisplayNameOf,
2611 SF_SetNameOf
2614 static IShellFolder ShellFolder = { &ShellFolderVtbl };
2616 static void test_SHIShellFolder_EnumObjects(void)
2618 IEnumIDList *enm;
2619 HRESULT hres;
2620 IShellFolder *folder;
2622 if(!pSHIShellFolder_EnumObjects){ /* win7 and later */
2623 win_skip("SHIShellFolder_EnumObjects not available\n");
2624 return;
2627 if(0){
2628 /* NULL object crashes on Windows */
2629 pSHIShellFolder_EnumObjects(NULL, NULL, 0, NULL);
2632 /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */
2633 enm = (IEnumIDList*)0xdeadbeef;
2634 hres = pSHIShellFolder_EnumObjects(&ShellFolder, NULL, 0, &enm);
2635 ok(hres == S_OK, "SHIShellFolder_EnumObjects failed: 0x%08x\n", hres);
2636 ok(enm == (IEnumIDList*)0xcafebabe, "Didn't get expected enumerator location, instead: %p\n", enm);
2638 /* SHIShellFolder_EnumObjects isn't strict about the IShellFolder object */
2639 hres = SHGetDesktopFolder(&folder);
2640 ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
2642 enm = NULL;
2643 hres = pSHIShellFolder_EnumObjects(folder, NULL, 0, &enm);
2644 ok(hres == S_OK, "SHIShellFolder_EnumObjects failed: 0x%08x\n", hres);
2645 ok(enm != NULL, "Didn't get an enumerator\n");
2646 if(enm)
2647 IEnumIDList_Release(enm);
2649 IShellFolder_Release(folder);
2652 static BOOL write_inifile(LPCWSTR filename)
2654 DWORD written;
2655 HANDLE file;
2657 static const char data[] =
2658 "[TestApp]\r\n"
2659 "AKey=1\r\n"
2660 "AnotherKey=asdf\r\n";
2662 file = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
2663 if(file == INVALID_HANDLE_VALUE) {
2664 win_skip("failed to create ini file at %s\n", wine_dbgstr_w(filename));
2665 return FALSE;
2668 WriteFile(file, data, sizeof(data), &written, NULL);
2670 CloseHandle(file);
2672 return TRUE;
2675 #define verify_inifile(f, e) r_verify_inifile(__LINE__, f, e)
2676 static void r_verify_inifile(unsigned l, LPCWSTR filename, LPCSTR exp)
2678 HANDLE file;
2679 CHAR buf[1024];
2680 DWORD read;
2682 file = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
2684 if(file == INVALID_HANDLE_VALUE)
2685 return;
2687 ReadFile(file, buf, sizeof(buf) * sizeof(CHAR), &read, NULL);
2688 buf[read] = '\0';
2690 CloseHandle(file);
2692 ok_(__FILE__,l)(!strcmp(buf, exp), "Expected:\n%s\nGot:\n%s\n", exp,
2693 buf);
2696 static void test_SHGetIniString(void)
2698 DWORD ret;
2699 WCHAR out[64] = {0};
2701 static const WCHAR TestAppW[] = {'T','e','s','t','A','p','p',0};
2702 static const WCHAR AKeyW[] = {'A','K','e','y',0};
2703 static const WCHAR AnotherKeyW[] = {'A','n','o','t','h','e','r','K','e','y',0};
2704 static const WCHAR JunkKeyW[] = {'J','u','n','k','K','e','y',0};
2705 static const WCHAR testpathW[] = {'C',':','\\','t','e','s','t','.','i','n','i',0};
2706 WCHAR pathW[MAX_PATH];
2708 lstrcpyW(pathW, testpathW);
2710 if (!write_inifile(pathW))
2711 return;
2713 if(0){
2714 /* these crash on Windows */
2715 pSHGetIniStringW(NULL, NULL, NULL, 0, NULL);
2716 pSHGetIniStringW(NULL, AKeyW, out, ARRAY_SIZE(out), pathW);
2717 pSHGetIniStringW(TestAppW, AKeyW, NULL, ARRAY_SIZE(out), pathW);
2720 ret = pSHGetIniStringW(TestAppW, AKeyW, out, 0, pathW);
2721 ok(ret == 0, "SHGetIniStringW should have given 0, instead: %d\n", ret);
2723 /* valid arguments */
2724 out[0] = 0;
2725 SetLastError(0xdeadbeef);
2726 ret = pSHGetIniStringW(TestAppW, NULL, out, ARRAY_SIZE(out), pathW);
2727 ok(ret == 4, "SHGetIniStringW should have given 4, instead: %d\n", ret);
2728 ok(!lstrcmpW(out, AKeyW), "Expected %s, got: %s, %d\n",
2729 wine_dbgstr_w(AKeyW), wine_dbgstr_w(out), GetLastError());
2731 ret = pSHGetIniStringW(TestAppW, AKeyW, out, ARRAY_SIZE(out), pathW);
2732 ok(ret == 1, "SHGetIniStringW should have given 1, instead: %d\n", ret);
2733 ok(!lstrcmpW(out, L"1"), "Expected L\"1\", got: %s\n", wine_dbgstr_w(out));
2735 ret = pSHGetIniStringW(TestAppW, AnotherKeyW, out, ARRAY_SIZE(out), pathW);
2736 ok(ret == 4, "SHGetIniStringW should have given 4, instead: %d\n", ret);
2737 ok(!lstrcmpW(out, L"asdf"), "Expected L\"asdf\", got: %s\n", wine_dbgstr_w(out));
2739 out[0] = 1;
2740 ret = pSHGetIniStringW(TestAppW, JunkKeyW, out, ARRAY_SIZE(out), pathW);
2741 ok(ret == 0, "SHGetIniStringW should have given 0, instead: %d\n", ret);
2742 ok(*out == 0, "Expected L\"\", got: %s\n", wine_dbgstr_w(out));
2744 DeleteFileW(pathW);
2747 static void test_SHSetIniString(void)
2749 BOOL ret;
2751 static const WCHAR TestAppW[] = {'T','e','s','t','A','p','p',0};
2752 static const WCHAR AnotherAppW[] = {'A','n','o','t','h','e','r','A','p','p',0};
2753 static const WCHAR TestIniW[] = {'C',':','\\','t','e','s','t','.','i','n','i',0};
2754 static const WCHAR AKeyW[] = {'A','K','e','y',0};
2755 static const WCHAR NewKeyW[] = {'N','e','w','K','e','y',0};
2756 static const WCHAR AValueW[] = {'A','V','a','l','u','e',0};
2758 if (!write_inifile(TestIniW))
2759 return;
2761 ret = pSHSetIniStringW(TestAppW, AKeyW, AValueW, TestIniW);
2762 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2763 todo_wine /* wine sticks an extra \r\n at the end of the file */
2764 verify_inifile(TestIniW, "[TestApp]\r\nAKey=AValue\r\nAnotherKey=asdf\r\n");
2766 ret = pSHSetIniStringW(TestAppW, AKeyW, NULL, TestIniW);
2767 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2768 verify_inifile(TestIniW, "[TestApp]\r\nAnotherKey=asdf\r\n");
2770 ret = pSHSetIniStringW(AnotherAppW, NewKeyW, AValueW, TestIniW);
2771 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2772 verify_inifile(TestIniW, "[TestApp]\r\nAnotherKey=asdf\r\n[AnotherApp]\r\nNewKey=AValue\r\n");
2774 ret = pSHSetIniStringW(TestAppW, NULL, AValueW, TestIniW);
2775 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2776 verify_inifile(TestIniW, "[AnotherApp]\r\nNewKey=AValue\r\n");
2778 DeleteFileW(TestIniW);
2781 enum _shellkey_flags {
2782 SHKEY_Root_HKCU = 0x1,
2783 SHKEY_Root_HKLM = 0x2,
2784 SHKEY_Key_Explorer = 0x00,
2785 SHKEY_Key_Shell = 0x10,
2786 SHKEY_Key_ShellNoRoam = 0x20,
2787 SHKEY_Key_Classes = 0x30,
2788 SHKEY_Subkey_Default = 0x0000,
2789 SHKEY_Subkey_ResourceName = 0x1000,
2790 SHKEY_Subkey_Handlers = 0x2000,
2791 SHKEY_Subkey_Associations = 0x3000,
2792 SHKEY_Subkey_Volatile = 0x4000,
2793 SHKEY_Subkey_MUICache = 0x5000,
2794 SHKEY_Subkey_FileExts = 0x6000
2797 static void test_SHGetShellKey(void)
2799 static const WCHAR ShellFoldersW[] = { 'S','h','e','l','l',' ','F','o','l','d','e','r','s',0 };
2800 static const WCHAR WineTestW[] = { 'W','i','n','e','T','e','s','t',0 };
2802 DWORD *alloc_data, data, size;
2803 HKEY hkey;
2804 HRESULT hres;
2806 /* Vista+ limits SHKEY enumeration values */
2807 SetLastError(0xdeadbeef);
2808 hkey = pSHGetShellKey(SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2809 if (hkey)
2811 /* Tests not working on Vista+ */
2812 RegCloseKey(hkey);
2814 hkey = pSHGetShellKey(SHKEY_Root_HKLM|SHKEY_Key_Classes, NULL, FALSE);
2815 ok(hkey != NULL, "hkey = NULL\n");
2816 RegCloseKey(hkey);
2819 hkey = pSHGetShellKey(SHKEY_Root_HKCU|SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2820 ok(hkey != NULL, "hkey = NULL\n");
2821 RegCloseKey(hkey);
2823 hkey = pSHGetShellKey(SHKEY_Root_HKLM|SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2824 ok(hkey != NULL, "hkey = NULL\n");
2825 RegCloseKey(hkey);
2827 hkey = pSHGetShellKey(SHKEY_Root_HKLM, WineTestW, FALSE);
2828 ok(hkey == NULL, "hkey != NULL\n");
2830 hkey = pSHGetShellKey(SHKEY_Root_HKLM, NULL, FALSE);
2831 ok(hkey != NULL, "Can't open key\n");
2832 ok(SUCCEEDED(RegDeleteKeyW(hkey, WineTestW)), "Can't delete key\n");
2833 RegCloseKey(hkey);
2835 hkey = pSHGetShellKey(SHKEY_Root_HKLM, WineTestW, TRUE);
2836 if (!hkey && GetLastError() == ERROR_ACCESS_DENIED)
2838 skip("Not authorized to create keys\n");
2839 return;
2841 ok(hkey != NULL, "Can't create key\n");
2842 RegCloseKey(hkey);
2844 size = sizeof(data);
2845 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
2846 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres);
2848 data = 1234;
2849 hres = pSKSetValueW(SHKEY_Root_HKLM, WineTestW, NULL, REG_DWORD, &data, sizeof(DWORD));
2850 ok(hres == S_OK, "hres = %x\n", hres);
2852 size = 1;
2853 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, NULL, &size);
2854 ok(hres == S_OK, "hres = %x\n", hres);
2855 ok(size == sizeof(DWORD), "size = %d\n", size);
2857 data = 0xdeadbeef;
2858 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
2859 ok(hres == S_OK, "hres = %x\n", hres);
2860 ok(size == sizeof(DWORD), "size = %d\n", size);
2861 ok(data == 1234, "data = %d\n", data);
2863 hres = pSKAllocValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, (void**)&alloc_data, &size);
2864 ok(hres == S_OK, "hres= %x\n", hres);
2865 ok(size == sizeof(DWORD), "size = %d\n", size);
2866 if (SUCCEEDED(hres))
2868 ok(*alloc_data == 1234, "*alloc_data = %d\n", *alloc_data);
2869 LocalFree(alloc_data);
2872 hres = pSKDeleteValueW(SHKEY_Root_HKLM, WineTestW, NULL);
2873 ok(hres == S_OK, "hres = %x\n", hres);
2875 hres = pSKDeleteValueW(SHKEY_Root_HKLM, WineTestW, NULL);
2876 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres);
2878 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
2879 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres);
2881 hkey = pSHGetShellKey(SHKEY_Root_HKLM, NULL, FALSE);
2882 ok(hkey != NULL, "Can't create key\n");
2883 ok(SUCCEEDED(RegDeleteKeyW(hkey, WineTestW)), "Can't delete key\n");
2884 RegCloseKey(hkey);
2887 static void init_pointers(void)
2889 #define MAKEFUNC(f, ord) (p##f = (void*)GetProcAddress(hShlwapi, (LPSTR)(ord)))
2890 MAKEFUNC(SHAllocShared, 7);
2891 MAKEFUNC(SHLockShared, 8);
2892 MAKEFUNC(SHUnlockShared, 9);
2893 MAKEFUNC(SHFreeShared, 10);
2894 MAKEFUNC(SHMapHandle, 11);
2895 MAKEFUNC(GetAcceptLanguagesA, 14);
2896 MAKEFUNC(SHSetWindowBits, 165);
2897 MAKEFUNC(SHSetParentHwnd, 167);
2898 MAKEFUNC(ConnectToConnectionPoint, 168);
2899 MAKEFUNC(IUnknown_GetClassID, 175);
2900 MAKEFUNC(SHSearchMapInt, 198);
2901 MAKEFUNC(SHCreateWorkerWindowA, 257);
2902 MAKEFUNC(GUIDFromStringA, 269);
2903 MAKEFUNC(SHPackDispParams, 282);
2904 MAKEFUNC(IConnectionPoint_InvokeWithCancel, 283);
2905 MAKEFUNC(IConnectionPoint_SimpleInvoke, 284);
2906 MAKEFUNC(SHGetIniStringW, 294);
2907 MAKEFUNC(SHSetIniStringW, 295);
2908 MAKEFUNC(SHFormatDateTimeA, 353);
2909 MAKEFUNC(SHFormatDateTimeW, 354);
2910 MAKEFUNC(SHIShellFolder_EnumObjects, 404);
2911 MAKEFUNC(GetShellSecurityDescriptor, 475);
2912 MAKEFUNC(SHGetObjectCompatFlags, 476);
2913 MAKEFUNC(IUnknown_QueryServiceExec, 484);
2914 MAKEFUNC(SHGetShellKey, 491);
2915 MAKEFUNC(SHPropertyBag_ReadLONG, 496);
2916 MAKEFUNC(IUnknown_ProfferService, 514);
2917 MAKEFUNC(SKGetValueW, 516);
2918 MAKEFUNC(SKSetValueW, 517);
2919 MAKEFUNC(SKDeleteValueW, 518);
2920 MAKEFUNC(SKAllocValueW, 519);
2921 #undef MAKEFUNC
2923 pDllGetVersion = (void*)GetProcAddress(hShlwapi, "DllGetVersion");
2926 static void test_SHSetParentHwnd(void)
2928 HWND hwnd, hwnd2, ret;
2929 DWORD style;
2931 hwnd = CreateWindowA("Button", "", WS_VISIBLE, 0, 0, 10, 10, NULL, NULL, NULL, NULL);
2932 ok(hwnd != NULL, "got %p\n", hwnd);
2934 hwnd2 = CreateWindowA("Button", "", WS_VISIBLE | WS_CHILD, 0, 0, 10, 10, hwnd, NULL, NULL, NULL);
2935 ok(hwnd2 != NULL, "got %p\n", hwnd2);
2937 /* null params */
2938 ret = pSHSetParentHwnd(NULL, NULL);
2939 ok(ret == NULL, "got %p\n", ret);
2941 /* set to no parent while already no parent present */
2942 ret = GetParent(hwnd);
2943 ok(ret == NULL, "got %p\n", ret);
2944 style = GetWindowLongA(hwnd, GWL_STYLE);
2945 ok((style & (WS_POPUP|WS_CHILD)) == 0, "got style 0x%08x\n", style);
2946 ret = pSHSetParentHwnd(hwnd, NULL);
2947 ok(ret == NULL, "got %p\n", ret);
2948 style = GetWindowLongA(hwnd, GWL_STYLE);
2949 ok((style & (WS_POPUP|WS_CHILD)) == 0, "got style 0x%08x\n", style);
2951 /* reset to null parent from not null */
2952 ret = GetParent(hwnd2);
2953 ok(ret == hwnd, "got %p\n", ret);
2954 style = GetWindowLongA(hwnd2, GWL_STYLE);
2955 ok((style & (WS_POPUP|WS_CHILD)) == WS_CHILD, "got style 0x%08x\n", style);
2956 ret = pSHSetParentHwnd(hwnd2, NULL);
2957 ok(ret == NULL, "got %p\n", ret);
2958 style = GetWindowLongA(hwnd2, GWL_STYLE);
2959 ok((style & (WS_POPUP|WS_CHILD)) == WS_POPUP, "got style 0x%08x\n", style);
2960 ret = GetParent(hwnd2);
2961 ok(ret == NULL, "got %p\n", ret);
2963 /* set parent back */
2964 style = GetWindowLongA(hwnd2, GWL_STYLE);
2965 SetWindowLongA(hwnd2, GWL_STYLE, style & ~(WS_CHILD|WS_POPUP));
2966 style = GetWindowLongA(hwnd2, GWL_STYLE);
2967 ok((style & (WS_CHILD|WS_POPUP)) == 0, "got 0x%08x\n", style);
2969 ret = pSHSetParentHwnd(hwnd2, hwnd);
2970 todo_wine ok(ret == NULL, "got %p\n", ret);
2972 style = GetWindowLongA(hwnd2, GWL_STYLE);
2973 ok((style & (WS_POPUP|WS_CHILD)) == WS_CHILD, "got style 0x%08x\n", style);
2974 ret = GetParent(hwnd2);
2975 ok(ret == hwnd, "got %p\n", ret);
2977 /* try to set same parent again */
2978 /* with WS_POPUP */
2979 style = GetWindowLongA(hwnd2, GWL_STYLE);
2980 SetWindowLongA(hwnd2, GWL_STYLE, style | WS_POPUP);
2981 ret = pSHSetParentHwnd(hwnd2, hwnd);
2982 todo_wine ok(ret == NULL, "got %p\n", ret);
2983 style = GetWindowLongA(hwnd2, GWL_STYLE);
2984 ok((style & (WS_CHILD|WS_POPUP)) == WS_CHILD, "got 0x%08x\n", style);
2985 ret = GetParent(hwnd2);
2986 ok(ret == hwnd, "got %p\n", ret);
2988 /* without WS_POPUP */
2989 style = GetWindowLongA(hwnd2, GWL_STYLE);
2990 SetWindowLongA(hwnd2, GWL_STYLE, style | ~WS_POPUP);
2991 ret = pSHSetParentHwnd(hwnd2, hwnd);
2992 todo_wine ok(ret == hwnd, "got %p\n", ret);
2993 style = GetWindowLongA(hwnd2, GWL_STYLE);
2994 ok((style & (WS_CHILD|WS_POPUP)) == WS_CHILD, "got 0x%08x\n", style);
2995 ret = GetParent(hwnd2);
2996 ok(ret == hwnd, "got %p\n", ret);
2998 DestroyWindow(hwnd);
2999 DestroyWindow(hwnd2);
3002 static HRESULT WINAPI testpersist_QI(IPersist *iface, REFIID riid, void **obj)
3004 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPersist)) {
3005 *obj = iface;
3006 IPersist_AddRef(iface);
3007 return S_OK;
3010 *obj = NULL;
3011 return E_NOINTERFACE;
3014 static HRESULT WINAPI testpersist_QI2(IPersist *iface, REFIID riid, void **obj)
3016 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPersistFolder)) {
3017 *obj = iface;
3018 IPersist_AddRef(iface);
3019 return S_OK;
3022 *obj = NULL;
3023 return E_NOINTERFACE;
3026 static ULONG WINAPI testpersist_AddRef(IPersist *iface)
3028 return 2;
3031 static ULONG WINAPI testpersist_Release(IPersist *iface)
3033 return 1;
3036 static HRESULT WINAPI testpersist_GetClassID(IPersist *iface, CLSID *clsid)
3038 memset(clsid, 0xab, sizeof(*clsid));
3039 return 0x8fff2222;
3042 static IPersistVtbl testpersistvtbl = {
3043 testpersist_QI,
3044 testpersist_AddRef,
3045 testpersist_Release,
3046 testpersist_GetClassID
3049 static IPersistVtbl testpersist2vtbl = {
3050 testpersist_QI2,
3051 testpersist_AddRef,
3052 testpersist_Release,
3053 testpersist_GetClassID
3056 static IPersist testpersist = { &testpersistvtbl };
3057 static IPersist testpersist2 = { &testpersist2vtbl };
3059 static void test_IUnknown_GetClassID(void)
3061 CLSID clsid, clsid2, clsid3;
3062 HRESULT hr;
3064 if (0) /* crashes on native systems */
3065 hr = pIUnknown_GetClassID(NULL, NULL);
3067 memset(&clsid, 0xcc, sizeof(clsid));
3068 memset(&clsid3, 0xcc, sizeof(clsid3));
3069 hr = pIUnknown_GetClassID(NULL, &clsid);
3070 ok(hr == E_FAIL, "got 0x%08x\n", hr);
3071 ok(IsEqualCLSID(&clsid, &CLSID_NULL) || broken(IsEqualCLSID(&clsid, &clsid3)) /* win2k, winxp, win2k3 */,
3072 "got wrong clsid %s\n", wine_dbgstr_guid(&clsid));
3074 memset(&clsid, 0xcc, sizeof(clsid));
3075 memset(&clsid2, 0xab, sizeof(clsid2));
3076 hr = pIUnknown_GetClassID((IUnknown*)&testpersist, &clsid);
3077 ok(hr == 0x8fff2222, "got 0x%08x\n", hr);
3078 ok(IsEqualCLSID(&clsid, &clsid2) || broken(IsEqualCLSID(&clsid, &clsid3)) /* win2k3 */,
3079 "got wrong clsid %s\n", wine_dbgstr_guid(&clsid));
3081 /* IPersistFolder is also supported */
3082 memset(&clsid, 0xcc, sizeof(clsid));
3083 memset(&clsid2, 0xab, sizeof(clsid2));
3084 memset(&clsid3, 0xcc, sizeof(clsid3));
3085 hr = pIUnknown_GetClassID((IUnknown*)&testpersist2, &clsid);
3086 ok(hr == 0x8fff2222, "got 0x%08x\n", hr);
3087 ok(IsEqualCLSID(&clsid, &clsid2) || broken(IsEqualCLSID(&clsid, &clsid3)) /* win2k3 */,
3088 "got wrong clsid %s\n", wine_dbgstr_guid(&clsid));
3091 static void test_DllGetVersion(void)
3093 HRESULT hr;
3095 hr = pDllGetVersion(NULL);
3096 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3099 START_TEST(ordinal)
3101 char **argv;
3102 int argc;
3104 hShlwapi = GetModuleHandleA("shlwapi.dll");
3106 init_pointers();
3108 argc = winetest_get_mainargs(&argv);
3109 if (argc >= 4)
3111 DWORD procid;
3112 HANDLE hmem;
3113 sscanf(argv[2], "%d", &procid);
3114 sscanf(argv[3], "%p", &hmem);
3115 test_alloc_shared_remote(procid, hmem);
3116 return;
3119 test_GetAcceptLanguagesA();
3120 test_SHSearchMapInt();
3121 test_alloc_shared(argc, argv);
3122 test_fdsa();
3123 test_GetShellSecurityDescriptor();
3124 test_SHPackDispParams();
3125 test_IConnectionPoint();
3126 test_SHPropertyBag_ReadLONG();
3127 test_SHSetWindowBits();
3128 test_SHFormatDateTimeA();
3129 test_SHFormatDateTimeW();
3130 test_SHGetObjectCompatFlags();
3131 test_IUnknown_QueryServiceExec();
3132 test_IUnknown_ProfferService();
3133 test_SHCreateWorkerWindowA();
3134 test_SHIShellFolder_EnumObjects();
3135 test_SHGetIniString();
3136 test_SHSetIniString();
3137 test_SHGetShellKey();
3138 test_SHSetParentHwnd();
3139 test_IUnknown_GetClassID();
3140 test_DllGetVersion();