shlwapi/tests: Enable compilation with long types.
[wine.git] / dlls / shlwapi / tests / ordinal.c
blob603a2ac2a7686936ca2c1cc568431b7dbd45b5a9
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: %ld\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%lx\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%lx 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 %ld 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%lx with %ld 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%lx with %ld 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%lx with %ld 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%lx with %ld 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%lx with %ld 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%lx with %ld 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%lx with %ld 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%lx with %ld 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%lx with %ld 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%lx\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%lx (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%lx (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: %ld\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: %lu\n", GetLastError());
464 ret = pSHFreeShared(hmem, procid);
465 ok( ret, "SHFreeShared failed: %lu\n", GetLastError());
467 val.value = 0x12345678;
468 val.handle = 0;
469 hmem = pSHAllocShared(&val, sizeof(val), procid);
470 ok(hmem!=NULL,"SHAllocShared(NULL...) failed: %lu\n", GetLastError());
472 p=pSHLockShared(hmem,procid);
473 ok(p!=NULL,"SHLockShared failed: %lu\n", GetLastError());
474 if (p!=NULL)
475 ok(p->value == 0x12345678, "Wrong value in shared memory: %ld instead of %d\n", p->value, 0x12345678);
476 ret = pSHUnlockShared(p);
477 ok( ret, "SHUnlockShared failed: %lu\n", GetLastError());
479 sprintf(cmdline, "%s %s %ld %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: %lu\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: %lu\n", GetLastError());
490 if (p != NULL && p->value != 0x12345678)
492 ok(p->value == 0x12345679, "Wrong value in shared memory: %ld 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: %lu\n", GetLastError());
500 ret = pSHFreeShared(hmem, procid);
501 ok( ret, "SHFreeShared failed: %lu\n", GetLastError());
503 if (hmem2)
505 p = pSHLockShared(hmem2, procid);
506 ok(p != NULL,"SHLockShared failed: %lu\n", GetLastError());
507 if (p != NULL)
508 ok(p->value == 0xDEADBEEF, "Wrong value in shared memory: %ld instead of %d\n", p->value, 0xDEADBEEF);
509 ret = pSHUnlockShared(p);
510 ok(ret, "SHUnlockShared failed: %lu\n", GetLastError());
512 ret = pSHFreeShared(hmem2, procid);
513 ok(ret, "SHFreeShared failed: %lu\n", GetLastError());
516 SetLastError(0xdeadbeef);
517 ret = pSHFreeShared(NULL, procid);
518 ok(ret, "SHFreeShared failed: %lu\n", GetLastError());
519 ok(GetLastError() == 0xdeadbeef, "last error should not have changed, got %lu\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: %lu\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: %ld 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: %lu\n", GetLastError());
545 ret = pSHUnlockShared(p);
546 ok(ret, "SHUnlockShared failed: %lu\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 %lu\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: %lu\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: %lu\n", GetLastError());
569 if (p != NULL)
570 ok(p->value == 0x12345679, "Wrong value in shared memory: %ld instead of %d\n", p->value, 0x12345679);
572 ret = pSHUnlockShared(p);
573 ok(ret, "SHUnlockShared failed: %lu\n", GetLastError());
575 ret = pSHFreeShared(hmem2, GetCurrentProcessId());
576 ok(ret, "SHFreeShared failed: %lu\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 = %ld\n", info.num_items);
612 ok(info.mem == mem, "mem = %p\n", info.mem);
613 ok(info.blocks_alloced == init_blocks, "blocks_alloced = %ld\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 = %ld\n", ret);
620 ok(info.num_items == 1, "num_items = %ld\n", info.num_items);
621 ok(info.mem == mem, "mem = %p\n", info.mem);
622 ok(info.blocks_alloced == init_blocks, "blocks_alloced = %ld\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 = %ld\n", ret);
630 ret = pFDSA_InsertItem(&info, 1, "klmnopqrst");
631 ok(ret == 1, "ret = %ld\n", ret);
633 ret = pFDSA_InsertItem(&info, 0, "uvwxyzABCD");
634 ok(ret == 0, "ret = %ld\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 = %ld\n", ret);
641 ok(info.mem != mem, "mem = %p\n", info.mem);
642 ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %ld\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 = %ld\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 = %ld\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 %lu\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 %lu\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 %lu\n", GetLastError());
740 ok(asiSize.AceCount == 3, "Incorrect number of ACEs: %ld 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 %lu\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 %lx\n", paaa->Mask);
752 ret = GetAce(pAcl, 1, (LPVOID*)&paaa);
753 ok(ret, "GetAce failed with error %lu\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 %lx\n", paaa->Mask);
760 ret = GetAce(pAcl, 2, (LPVOID*)&paaa);
761 ok(ret, "GetAce failed with error %lu\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 %lx\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: %08lx\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 %lx\n", V_I4(vars));
793 memset(&params, 0xc0, sizeof(params));
794 hres = pSHPackDispParams(&params, NULL, 0, 0);
795 ok(hres == S_OK, "SHPackDispParams failed: %08lx\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: %08lx\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]) = %lx\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]) = %lx\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]) = %lx\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 %lx %s %lx %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 %lx\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 %lx\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 IConnectionPoint_AddRef(*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->IDispatch_iface, &IID_NULL, TRUE,
1463 (IUnknown*)&container->IConnectionPointContainer_iface, &cookie, &point);
1464 ok(rc == S_OK, "pConnectToConnectionPoint failed with %lx\n",rc);
1465 ok(point != NULL, "returned ConnectionPoint is NULL\n");
1466 ok(cookie != 0xffffffff, "invalid cookie returned\n");
1468 rc = pIConnectionPoint_SimpleInvoke(point,0xa0,NULL);
1469 ok(rc == S_OK, "pConnectToConnectionPoint failed with %lx\n",rc);
1471 memset(&params, 0xc0, sizeof(params));
1472 memset(vars, 0xc0, sizeof(vars));
1473 rc = pSHPackDispParams(&params, vars, 2, VT_I4, 0xdeadbeef, VT_BSTR, 0xdeadcafe);
1474 ok(rc == S_OK, "SHPackDispParams failed: %08lx\n", rc);
1476 rc = pIConnectionPoint_SimpleInvoke(point,0xa1,&params);
1477 ok(rc == S_OK, "pConnectToConnectionPoint failed with %lx\n",rc);
1479 rc = pConnectToConnectionPoint(NULL, &IID_NULL, FALSE,
1480 (IUnknown*)&container->IConnectionPointContainer_iface, &cookie, NULL);
1481 ok(rc == S_OK, "pConnectToConnectionPoint failed with %lx\n",rc);
1483 /* MSDN says this should be required but it crashes on XP
1484 IUnknown_Release(point);
1486 ref = IConnectionPointContainer_Release(&container->IConnectionPointContainer_iface);
1487 ok(ref == 0, "leftover IConnectionPointContainer reference %li\n",ref);
1488 ref = IDispatch_Release(&dispatch->IDispatch_iface);
1489 ok(ref == 0, "leftover IDispatch reference %li\n",ref);
1492 typedef struct _propbag
1494 IPropertyBag IPropertyBag_iface;
1495 LONG refCount;
1497 } PropBag;
1499 static inline PropBag *impl_from_IPropertyBag(IPropertyBag *iface)
1501 return CONTAINING_RECORD(iface, PropBag, IPropertyBag_iface);
1505 static HRESULT WINAPI Prop_QueryInterface(
1506 IPropertyBag* This,
1507 REFIID riid,
1508 void **ppvObject)
1510 *ppvObject = NULL;
1512 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPropertyBag))
1514 *ppvObject = This;
1517 if (*ppvObject)
1519 IPropertyBag_AddRef(This);
1520 return S_OK;
1523 trace("no interface\n");
1524 return E_NOINTERFACE;
1527 static ULONG WINAPI Prop_AddRef(
1528 IPropertyBag* This)
1530 PropBag *iface = impl_from_IPropertyBag(This);
1531 return InterlockedIncrement(&iface->refCount);
1534 static ULONG WINAPI Prop_Release(
1535 IPropertyBag* This)
1537 PropBag *iface = impl_from_IPropertyBag(This);
1538 ULONG ret;
1540 ret = InterlockedDecrement(&iface->refCount);
1541 if (ret == 0)
1542 HeapFree(GetProcessHeap(),0,This);
1543 return ret;
1546 static HRESULT WINAPI Prop_Read(
1547 IPropertyBag* This,
1548 LPCOLESTR pszPropName,
1549 VARIANT *pVar,
1550 IErrorLog *pErrorLog)
1552 V_VT(pVar) = VT_BLOB|VT_BYREF;
1553 V_BYREF(pVar) = (LPVOID)0xdeadcafe;
1554 return S_OK;
1557 static HRESULT WINAPI Prop_Write(
1558 IPropertyBag* This,
1559 LPCOLESTR pszPropName,
1560 VARIANT *pVar)
1562 return S_OK;
1566 static const IPropertyBagVtbl prop_vtbl = {
1567 Prop_QueryInterface,
1568 Prop_AddRef,
1569 Prop_Release,
1571 Prop_Read,
1572 Prop_Write
1575 static void test_SHPropertyBag_ReadLONG(void)
1577 PropBag *pb;
1578 HRESULT rc;
1579 LONG out;
1580 static const WCHAR szName1[] = {'n','a','m','e','1',0};
1582 pb = HeapAlloc(GetProcessHeap(),0,sizeof(PropBag));
1583 pb->refCount = 1;
1584 pb->IPropertyBag_iface.lpVtbl = &prop_vtbl;
1586 out = 0xfeedface;
1587 rc = pSHPropertyBag_ReadLONG(NULL, szName1, &out);
1588 ok(rc == E_INVALIDARG || broken(rc == S_OK), "incorrect return %lx\n",rc);
1589 ok(out == 0xfeedface, "value should not have changed\n");
1590 rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, NULL, &out);
1591 ok(rc == E_INVALIDARG || broken(rc == S_OK) || broken(rc == S_FALSE), "incorrect return %lx\n",rc);
1592 ok(out == 0xfeedface, "value should not have changed\n");
1593 rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, szName1, NULL);
1594 ok(rc == E_INVALIDARG || broken(rc == S_OK) || broken(rc == S_FALSE), "incorrect return %lx\n",rc);
1595 rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, szName1, &out);
1596 ok(rc == DISP_E_BADVARTYPE || broken(rc == S_OK) || broken(rc == S_FALSE), "incorrect return %lx\n",rc);
1597 ok(out == 0xfeedface || broken(out == 0xfeedfa00), "value should not have changed %lx\n",out);
1598 IPropertyBag_Release(&pb->IPropertyBag_iface);
1601 static void test_SHSetWindowBits(void)
1603 HWND hwnd;
1604 DWORD style, styleold;
1605 WNDCLASSA clsA;
1607 clsA.style = 0;
1608 clsA.lpfnWndProc = DefWindowProcA;
1609 clsA.cbClsExtra = 0;
1610 clsA.cbWndExtra = 0;
1611 clsA.hInstance = GetModuleHandleA(NULL);
1612 clsA.hIcon = 0;
1613 clsA.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
1614 clsA.hbrBackground = NULL;
1615 clsA.lpszMenuName = NULL;
1616 clsA.lpszClassName = "Shlwapi test class";
1617 RegisterClassA(&clsA);
1619 hwnd = CreateWindowA("Shlwapi test class", "Test", WS_VISIBLE, 0, 0, 100, 100,
1620 NULL, NULL, GetModuleHandleA(NULL), 0);
1621 ok(IsWindow(hwnd), "failed to create window\n");
1623 /* null window */
1624 SetLastError(0xdeadbeef);
1625 style = pSHSetWindowBits(NULL, GWL_STYLE, 0, 0);
1626 ok(style == 0, "expected 0 retval, got %ld\n", style);
1627 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE,
1628 "expected ERROR_INVALID_WINDOW_HANDLE, got %ld\n", GetLastError());
1630 /* zero mask, zero flags */
1631 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1632 style = pSHSetWindowBits(hwnd, GWL_STYLE, 0, 0);
1633 ok(styleold == style, "expected old style\n");
1634 ok(styleold == GetWindowLongA(hwnd, GWL_STYLE), "expected to keep old style\n");
1636 /* test mask */
1637 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1638 ok(styleold & WS_VISIBLE, "expected WS_VISIBLE\n");
1639 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1641 ok(style == styleold, "expected previous style, got %lx\n", style);
1642 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1644 /* test mask, unset style bit used */
1645 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1646 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1647 ok(style == styleold, "expected previous style, got %lx\n", style);
1648 ok(styleold == GetWindowLongA(hwnd, GWL_STYLE), "expected to keep old style\n");
1650 /* set back with flags */
1651 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1652 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, WS_VISIBLE);
1653 ok(style == styleold, "expected previous style, got %lx\n", style);
1654 ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "expected updated style\n");
1656 /* reset and try to set without a mask */
1657 pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1658 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1659 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1660 style = pSHSetWindowBits(hwnd, GWL_STYLE, 0, WS_VISIBLE);
1661 ok(style == styleold, "expected previous style, got %lx\n", style);
1662 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1664 DestroyWindow(hwnd);
1666 UnregisterClassA("Shlwapi test class", GetModuleHandleA(NULL));
1669 static void test_SHFormatDateTimeA(void)
1671 FILETIME UNALIGNED filetime;
1672 CHAR buff[100], buff2[100], buff3[100];
1673 SYSTEMTIME st;
1674 DWORD flags;
1675 INT ret;
1677 GetLocalTime(&st);
1678 SystemTimeToFileTime(&st, &filetime);
1679 /* SHFormatDateTime expects input as utc */
1680 LocalFileTimeToFileTime(&filetime, &filetime);
1682 /* no way to get required buffer length here */
1683 ret = pSHFormatDateTimeA(&filetime, NULL, NULL, 0);
1684 ok(ret == 0, "got %d\n", ret);
1686 SetLastError(0xdeadbeef);
1687 buff[0] = 'a'; buff[1] = 0;
1688 ret = pSHFormatDateTimeA(&filetime, NULL, buff, 0);
1689 ok(ret == 0, "got %d\n", ret);
1690 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError());
1691 ok(buff[0] == 'a', "expected same string, got %s\n", buff);
1693 /* flags needs to have FDTF_NOAUTOREADINGORDER for these tests to succeed on Vista+ */
1695 /* all combinations documented as invalid succeeded */
1696 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTTIME | FDTF_LONGTIME;
1697 SetLastError(0xdeadbeef);
1698 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1699 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1700 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError());
1702 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_LONGDATE;
1703 SetLastError(0xdeadbeef);
1704 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1705 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1706 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError());
1708 flags = FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE;
1709 SetLastError(0xdeadbeef);
1710 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1711 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1712 ok(GetLastError() == 0xdeadbeef,
1713 "expected 0xdeadbeef, got %ld\n", GetLastError());
1715 flags = FDTF_DEFAULT;
1716 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1717 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1719 buff2[0] = '\0';
1720 flags = FDTF_SHORTDATE | FDTF_SHORTTIME;
1721 ret = pSHFormatDateTimeA(&filetime, &flags, buff2, sizeof(buff2));
1722 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1723 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff, buff2);
1725 buff2[0] = '\0';
1726 ret = pSHFormatDateTimeA(&filetime, NULL, buff2, sizeof(buff2));
1727 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1728 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff, buff2);
1730 /* now check returned strings */
1731 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTTIME;
1732 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1733 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1734 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff2, sizeof(buff2));
1735 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1736 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1738 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGTIME;
1739 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1740 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1741 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2));
1742 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1743 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1745 /* both time flags */
1746 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGTIME | FDTF_SHORTTIME;
1747 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1748 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1749 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2));
1750 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1751 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1753 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE;
1754 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1755 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1756 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1757 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1758 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1760 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE;
1761 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1762 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1763 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1764 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1765 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1767 /* both date flags */
1768 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_SHORTDATE;
1769 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1770 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1771 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1772 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1773 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1775 /* various combinations of date/time flags */
1776 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_SHORTTIME;
1777 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1778 ok(ret == lstrlenA(buff)+1, "got %d, length %d\n", ret, lstrlenA(buff)+1);
1779 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3));
1780 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1781 ok(lstrcmpA(buff3, buff + lstrlenA(buff) - lstrlenA(buff3)) == 0,
1782 "expected (%s), got (%s) for time part\n",
1783 buff3, buff + lstrlenA(buff) - lstrlenA(buff3));
1784 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1785 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1786 buff[lstrlenA(buff2)] = '\0';
1787 ok(lstrcmpA(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1788 buff2, buff);
1790 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_LONGTIME;
1791 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1792 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1793 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3));
1794 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1795 ok(lstrcmpA(buff3, buff + lstrlenA(buff) - lstrlenA(buff3)) == 0,
1796 "expected (%s), got (%s) for time part\n",
1797 buff3, buff + lstrlenA(buff) - lstrlenA(buff3));
1798 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1799 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1800 buff[lstrlenA(buff2)] = '\0';
1801 ok(lstrcmpA(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1802 buff2, buff);
1804 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_SHORTTIME;
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, TIME_NOSECONDS, &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);
1815 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_LONGTIME;
1816 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1817 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1818 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1819 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1820 strcat(buff2, " ");
1821 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3));
1822 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1823 strcat(buff2, buff3);
1824 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1827 static void test_SHFormatDateTimeW(void)
1829 FILETIME UNALIGNED filetime;
1830 WCHAR buff[100], buff2[100], buff3[100], *p1, *p2;
1831 SYSTEMTIME st;
1832 DWORD flags;
1833 INT ret;
1834 static const WCHAR spaceW[] = {' ',0};
1835 #define UNICODE_LTR_MARK 0x200e
1836 #define UNICODE_RTL_MARK 0x200f
1838 if (0)
1840 /* crashes on native */
1841 pSHFormatDateTimeW(NULL, NULL, NULL, 0);
1844 GetLocalTime(&st);
1845 SystemTimeToFileTime(&st, &filetime);
1846 /* SHFormatDateTime expects input as utc */
1847 LocalFileTimeToFileTime(&filetime, &filetime);
1849 /* no way to get required buffer length here */
1850 SetLastError(0xdeadbeef);
1851 ret = pSHFormatDateTimeW(&filetime, NULL, NULL, 0);
1852 ok(ret == 0, "expected 0, got %d\n", ret);
1853 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError());
1855 SetLastError(0xdeadbeef);
1856 buff[0] = 'a'; buff[1] = 0;
1857 ret = pSHFormatDateTimeW(&filetime, NULL, buff, 0);
1858 ok(ret == 0, "expected 0, got %d\n", ret);
1859 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError());
1860 ok(buff[0] == 'a', "expected same string\n");
1862 /* all combinations documented as invalid succeeded */
1863 flags = FDTF_SHORTTIME | FDTF_LONGTIME;
1864 SetLastError(0xdeadbeef);
1865 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1866 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1867 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1868 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError());
1870 flags = FDTF_SHORTDATE | FDTF_LONGDATE;
1871 SetLastError(0xdeadbeef);
1872 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1873 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1874 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1875 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError());
1877 flags = FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE;
1878 SetLastError(0xdeadbeef);
1879 buff[0] = 0; /* NT4 doesn't clear the buffer on failure */
1880 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1881 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1882 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1883 ok(GetLastError() == 0xdeadbeef,
1884 "expected 0xdeadbeef, got %ld\n", GetLastError());
1886 /* now check returned strings */
1887 flags = FDTF_SHORTTIME;
1888 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1889 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1890 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1891 SetLastError(0xdeadbeef);
1892 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff2, ARRAY_SIZE(buff2));
1893 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1894 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1896 flags = FDTF_LONGTIME;
1897 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1898 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1899 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1900 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, ARRAY_SIZE(buff2));
1901 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1902 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1904 /* both time flags */
1905 flags = FDTF_LONGTIME | FDTF_SHORTTIME;
1906 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1907 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1908 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1909 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, ARRAY_SIZE(buff2));
1910 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1911 ok(lstrcmpW(buff, buff2) == 0, "expected equal string\n");
1913 flags = FDTF_SHORTDATE;
1914 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1915 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1916 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1917 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, ARRAY_SIZE(buff2));
1918 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1919 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1921 flags = FDTF_LONGDATE;
1922 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1923 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1924 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1925 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, ARRAY_SIZE(buff2));
1926 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1927 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1929 /* both date flags */
1930 flags = FDTF_LONGDATE | FDTF_SHORTDATE;
1931 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1932 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1933 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1934 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, ARRAY_SIZE(buff2));
1935 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1936 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1938 /* various combinations of date/time flags */
1939 flags = FDTF_LONGDATE | FDTF_SHORTTIME;
1940 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1941 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1942 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1943 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, ARRAY_SIZE(buff3));
1944 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1945 ok(lstrcmpW(buff3, buff + lstrlenW(buff) - lstrlenW(buff3)) == 0,
1946 "expected (%s), got (%s) for time part\n",
1947 wine_dbgstr_w(buff3), wine_dbgstr_w(buff + lstrlenW(buff) - lstrlenW(buff3)));
1948 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, ARRAY_SIZE(buff2));
1949 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1950 p1 = buff;
1951 p2 = buff2;
1952 while (*p2 != '\0')
1954 while (*p1 == UNICODE_LTR_MARK || *p1 == UNICODE_RTL_MARK)
1955 p1++;
1956 while (*p2 == UNICODE_LTR_MARK || *p2 == UNICODE_RTL_MARK)
1957 p2++;
1958 p1++;
1959 p2++;
1961 *p1 = '\0';
1962 ok(lstrcmpW(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1963 wine_dbgstr_w(buff2), wine_dbgstr_w(buff));
1965 flags = FDTF_LONGDATE | FDTF_LONGTIME;
1966 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1967 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1968 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1969 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, ARRAY_SIZE(buff3));
1970 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1971 ok(lstrcmpW(buff3, buff + lstrlenW(buff) - lstrlenW(buff3)) == 0,
1972 "expected (%s), got (%s) for time part\n",
1973 wine_dbgstr_w(buff3), wine_dbgstr_w(buff + lstrlenW(buff) - lstrlenW(buff3)));
1974 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, ARRAY_SIZE(buff2));
1975 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1976 p1 = buff;
1977 p2 = buff2;
1978 while (*p2 != '\0')
1980 while (*p1 == UNICODE_LTR_MARK || *p1 == UNICODE_RTL_MARK)
1981 p1++;
1982 while (*p2 == UNICODE_LTR_MARK || *p2 == UNICODE_RTL_MARK)
1983 p2++;
1984 p1++;
1985 p2++;
1987 *p1 = '\0';
1988 ok(lstrcmpW(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1989 wine_dbgstr_w(buff2), wine_dbgstr_w(buff));
1991 flags = FDTF_SHORTDATE | FDTF_SHORTTIME;
1992 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1993 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1994 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1995 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, ARRAY_SIZE(buff2));
1996 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1997 lstrcatW(buff2, spaceW);
1998 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, ARRAY_SIZE(buff3));
1999 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
2000 lstrcatW(buff2, buff3);
2001 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
2003 flags = FDTF_SHORTDATE | FDTF_LONGTIME;
2004 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
2005 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
2006 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
2007 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, ARRAY_SIZE(buff2));
2008 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
2009 lstrcatW(buff2, spaceW);
2010 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, ARRAY_SIZE(buff3));
2011 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
2012 lstrcatW(buff2, buff3);
2013 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
2016 static void test_SHGetObjectCompatFlags(void)
2018 struct compat_value {
2019 CHAR nameA[30];
2020 DWORD value;
2023 struct compat_value values[] = {
2024 { "OTNEEDSSFCACHE", 0x1 },
2025 { "NO_WEBVIEW", 0x2 },
2026 { "UNBINDABLE", 0x4 },
2027 { "PINDLL", 0x8 },
2028 { "NEEDSFILESYSANCESTOR", 0x10 },
2029 { "NOTAFILESYSTEM", 0x20 },
2030 { "CTXMENU_NOVERBS", 0x40 },
2031 { "CTXMENU_LIMITEDQI", 0x80 },
2032 { "COCREATESHELLFOLDERONLY", 0x100 },
2033 { "NEEDSSTORAGEANCESTOR", 0x200 },
2034 { "NOLEGACYWEBVIEW", 0x400 },
2035 { "CTXMENU_XPQCMFLAGS", 0x1000 },
2036 { "NOIPROPERTYSTORE", 0x2000 }
2039 static const char compat_path[] = "Software\\Microsoft\\Windows\\CurrentVersion\\ShellCompatibility\\Objects";
2040 CHAR keyA[39]; /* {CLSID} */
2041 HKEY root;
2042 DWORD ret;
2043 int i;
2045 /* null args */
2046 ret = pSHGetObjectCompatFlags(NULL, NULL);
2047 ok(ret == 0, "got %ld\n", ret);
2049 ret = RegOpenKeyA(HKEY_LOCAL_MACHINE, compat_path, &root);
2050 if (ret != ERROR_SUCCESS)
2052 skip("No compatibility class data found\n");
2053 return;
2056 for (i = 0; RegEnumKeyA(root, i, keyA, sizeof(keyA)) == ERROR_SUCCESS; i++)
2058 HKEY clsid_key;
2060 if (RegOpenKeyA(root, keyA, &clsid_key) == ERROR_SUCCESS)
2062 CHAR valueA[30];
2063 DWORD expected = 0, got, length = sizeof(valueA);
2064 CLSID clsid;
2065 int v;
2067 for (v = 0; RegEnumValueA(clsid_key, v, valueA, &length, NULL, NULL, NULL, NULL) == ERROR_SUCCESS; v++)
2069 int j;
2071 for (j = 0; j < ARRAY_SIZE(values); j++)
2072 if (lstrcmpA(values[j].nameA, valueA) == 0)
2074 expected |= values[j].value;
2075 break;
2078 length = sizeof(valueA);
2081 pGUIDFromStringA(keyA, &clsid);
2082 got = pSHGetObjectCompatFlags(NULL, &clsid);
2083 ok(got == expected, "got 0x%08lx, expected 0x%08lx. Key %s\n", got, expected, keyA);
2085 RegCloseKey(clsid_key);
2089 RegCloseKey(root);
2092 typedef struct {
2093 IOleCommandTarget IOleCommandTarget_iface;
2094 LONG ref;
2095 } IOleCommandTargetImpl;
2097 static inline IOleCommandTargetImpl *impl_from_IOleCommandTarget(IOleCommandTarget *iface)
2099 return CONTAINING_RECORD(iface, IOleCommandTargetImpl, IOleCommandTarget_iface);
2102 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl;
2104 static IOleCommandTarget* IOleCommandTargetImpl_Construct(void)
2106 IOleCommandTargetImpl *obj;
2108 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2109 obj->IOleCommandTarget_iface.lpVtbl = &IOleCommandTargetImpl_Vtbl;
2110 obj->ref = 1;
2112 return &obj->IOleCommandTarget_iface;
2115 static HRESULT WINAPI IOleCommandTargetImpl_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppvObj)
2117 IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface);
2119 if (IsEqualIID(riid, &IID_IUnknown) ||
2120 IsEqualIID(riid, &IID_IOleCommandTarget))
2122 *ppvObj = This;
2125 if(*ppvObj)
2127 IOleCommandTarget_AddRef(iface);
2128 return S_OK;
2131 return E_NOINTERFACE;
2134 static ULONG WINAPI IOleCommandTargetImpl_AddRef(IOleCommandTarget *iface)
2136 IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface);
2137 return InterlockedIncrement(&This->ref);
2140 static ULONG WINAPI IOleCommandTargetImpl_Release(IOleCommandTarget *iface)
2142 IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface);
2143 ULONG ref = InterlockedDecrement(&This->ref);
2145 if (!ref)
2147 HeapFree(GetProcessHeap(), 0, This);
2148 return 0;
2150 return ref;
2153 static HRESULT WINAPI IOleCommandTargetImpl_QueryStatus(
2154 IOleCommandTarget *iface, const GUID *group, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText)
2156 return E_NOTIMPL;
2159 static HRESULT WINAPI IOleCommandTargetImpl_Exec(
2160 IOleCommandTarget *iface,
2161 const GUID *CmdGroup,
2162 DWORD nCmdID,
2163 DWORD nCmdexecopt,
2164 VARIANT *pvaIn,
2165 VARIANT *pvaOut)
2167 add_call(&trace_got, 3, CmdGroup, (void*)(DWORD_PTR)nCmdID, (void*)(DWORD_PTR)nCmdexecopt, pvaIn, pvaOut);
2168 return S_OK;
2171 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl =
2173 IOleCommandTargetImpl_QueryInterface,
2174 IOleCommandTargetImpl_AddRef,
2175 IOleCommandTargetImpl_Release,
2176 IOleCommandTargetImpl_QueryStatus,
2177 IOleCommandTargetImpl_Exec
2180 typedef struct {
2181 IServiceProvider IServiceProvider_iface;
2182 LONG ref;
2183 } IServiceProviderImpl;
2185 static inline IServiceProviderImpl *impl_from_IServiceProvider(IServiceProvider *iface)
2187 return CONTAINING_RECORD(iface, IServiceProviderImpl, IServiceProvider_iface);
2190 typedef struct {
2191 IProfferService IProfferService_iface;
2192 LONG ref;
2193 } IProfferServiceImpl;
2195 static inline IProfferServiceImpl *impl_from_IProfferService(IProfferService *iface)
2197 return CONTAINING_RECORD(iface, IProfferServiceImpl, IProfferService_iface);
2201 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl;
2202 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl;
2204 static IServiceProvider* IServiceProviderImpl_Construct(void)
2206 IServiceProviderImpl *obj;
2208 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2209 obj->IServiceProvider_iface.lpVtbl = &IServiceProviderImpl_Vtbl;
2210 obj->ref = 1;
2212 return &obj->IServiceProvider_iface;
2215 static IProfferService* IProfferServiceImpl_Construct(void)
2217 IProfferServiceImpl *obj;
2219 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2220 obj->IProfferService_iface.lpVtbl = &IProfferServiceImpl_Vtbl;
2221 obj->ref = 1;
2223 return &obj->IProfferService_iface;
2226 static HRESULT WINAPI IServiceProviderImpl_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppvObj)
2228 IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
2230 if (IsEqualIID(riid, &IID_IUnknown) ||
2231 IsEqualIID(riid, &IID_IServiceProvider))
2233 *ppvObj = This;
2236 if(*ppvObj)
2238 IServiceProvider_AddRef(iface);
2239 /* native uses redefined IID_IServiceProvider symbol, so we can't compare pointers */
2240 if (IsEqualIID(riid, &IID_IServiceProvider))
2241 add_call(&trace_got, 1, iface, &IID_IServiceProvider, 0, 0, 0);
2242 return S_OK;
2245 return E_NOINTERFACE;
2248 static ULONG WINAPI IServiceProviderImpl_AddRef(IServiceProvider *iface)
2250 IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
2251 return InterlockedIncrement(&This->ref);
2254 static ULONG WINAPI IServiceProviderImpl_Release(IServiceProvider *iface)
2256 IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
2257 ULONG ref = InterlockedDecrement(&This->ref);
2259 if (!ref)
2261 HeapFree(GetProcessHeap(), 0, This);
2262 return 0;
2264 return ref;
2267 static HRESULT WINAPI IServiceProviderImpl_QueryService(
2268 IServiceProvider *iface, REFGUID service, REFIID riid, void **ppv)
2270 /* native uses redefined pointer for IID_IOleCommandTarget, not one from uuid.lib */
2271 if (IsEqualIID(riid, &IID_IOleCommandTarget))
2273 add_call(&trace_got, 2, iface, service, &IID_IOleCommandTarget, 0, 0);
2274 *ppv = IOleCommandTargetImpl_Construct();
2276 if (IsEqualIID(riid, &IID_IProfferService))
2278 if (IsEqualIID(service, &IID_IProfferService))
2279 add_call(&trace_got, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2280 *ppv = IProfferServiceImpl_Construct();
2282 return S_OK;
2285 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl =
2287 IServiceProviderImpl_QueryInterface,
2288 IServiceProviderImpl_AddRef,
2289 IServiceProviderImpl_Release,
2290 IServiceProviderImpl_QueryService
2293 static void test_IUnknown_QueryServiceExec(void)
2295 IServiceProvider *provider;
2296 static const GUID dummy_serviceid = { 0xdeadbeef };
2297 static const GUID dummy_groupid = { 0xbeefbeef };
2298 call_trace_t trace_expected;
2299 HRESULT hr;
2301 provider = IServiceProviderImpl_Construct();
2303 /* null source pointer */
2304 hr = pIUnknown_QueryServiceExec(NULL, &dummy_serviceid, &dummy_groupid, 0, 0, 0, 0);
2305 ok(hr == E_FAIL ||
2306 hr == E_NOTIMPL, /* win 8 */
2307 "got 0x%08lx\n", hr);
2309 /* expected trace:
2310 IUnknown_QueryServiceExec( ptr1, serviceid, groupid, arg1, arg2, arg3, arg4);
2311 -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &prov );
2312 -> IServiceProvider_QueryService( prov, serviceid, &IID_IOleCommandTarget, &obj );
2313 -> IOleCommandTarget_Exec( obj, groupid, arg1, arg2, arg3, arg4 );
2315 init_call_trace(&trace_expected);
2317 add_call(&trace_expected, 1, provider, &IID_IServiceProvider, 0, 0, 0);
2318 add_call(&trace_expected, 2, provider, &dummy_serviceid, &IID_IOleCommandTarget, 0, 0);
2319 add_call(&trace_expected, 3, &dummy_groupid, (void*)0x1, (void*)0x2, (void*)0x3, (void*)0x4);
2321 init_call_trace(&trace_got);
2322 hr = pIUnknown_QueryServiceExec((IUnknown*)provider, &dummy_serviceid, &dummy_groupid, 0x1, 0x2, (void*)0x3, (void*)0x4);
2323 ok(hr == S_OK, "got 0x%08lx\n", hr);
2325 ok_trace(&trace_expected, &trace_got);
2327 free_call_trace(&trace_expected);
2328 free_call_trace(&trace_got);
2330 IServiceProvider_Release(provider);
2334 static HRESULT WINAPI IProfferServiceImpl_QueryInterface(IProfferService *iface, REFIID riid, void **ppvObj)
2336 IProfferServiceImpl *This = impl_from_IProfferService(iface);
2338 if (IsEqualIID(riid, &IID_IUnknown) ||
2339 IsEqualIID(riid, &IID_IProfferService))
2341 *ppvObj = This;
2343 else if (IsEqualIID(riid, &IID_IServiceProvider))
2345 *ppvObj = IServiceProviderImpl_Construct();
2346 add_call(&trace_got, 1, iface, &IID_IServiceProvider, 0, 0, 0);
2347 return S_OK;
2350 if(*ppvObj)
2352 IProfferService_AddRef(iface);
2353 return S_OK;
2356 return E_NOINTERFACE;
2359 static ULONG WINAPI IProfferServiceImpl_AddRef(IProfferService *iface)
2361 IProfferServiceImpl *This = impl_from_IProfferService(iface);
2362 return InterlockedIncrement(&This->ref);
2365 static ULONG WINAPI IProfferServiceImpl_Release(IProfferService *iface)
2367 IProfferServiceImpl *This = impl_from_IProfferService(iface);
2368 ULONG ref = InterlockedDecrement(&This->ref);
2370 if (!ref)
2372 HeapFree(GetProcessHeap(), 0, This);
2373 return 0;
2375 return ref;
2378 static HRESULT WINAPI IProfferServiceImpl_ProfferService(IProfferService *iface,
2379 REFGUID service, IServiceProvider *pService, DWORD *pCookie)
2381 *pCookie = 0xdeadbeef;
2382 add_call(&trace_got, 3, service, pService, pCookie, 0, 0);
2383 return S_OK;
2386 static HRESULT WINAPI IProfferServiceImpl_RevokeService(IProfferService *iface, DWORD cookie)
2388 add_call(&trace_got, 4, (void*)(DWORD_PTR)cookie, 0, 0, 0, 0);
2389 return S_OK;
2392 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl =
2394 IProfferServiceImpl_QueryInterface,
2395 IProfferServiceImpl_AddRef,
2396 IProfferServiceImpl_Release,
2397 IProfferServiceImpl_ProfferService,
2398 IProfferServiceImpl_RevokeService
2401 static void test_IUnknown_ProfferService(void)
2403 IServiceProvider *provider;
2404 IProfferService *proff;
2405 static const GUID dummy_serviceid = { 0xdeadbeef };
2406 call_trace_t trace_expected;
2407 HRESULT hr;
2408 DWORD cookie;
2410 provider = IServiceProviderImpl_Construct();
2411 proff = IProfferServiceImpl_Construct();
2413 /* null source pointer */
2414 hr = pIUnknown_ProfferService(NULL, &dummy_serviceid, 0, 0);
2415 ok(hr == E_FAIL ||
2416 hr == E_NOTIMPL, /* win 8 */
2417 "got 0x%08lx\n", hr);
2419 /* expected trace:
2420 IUnknown_ProfferService( ptr1, serviceid, arg1, arg2);
2421 -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &provider );
2422 -> IServiceProvider_QueryService( provider, &IID_IProfferService, &IID_IProfferService, &proffer );
2424 if (service pointer not null):
2425 -> IProfferService_ProfferService( proffer, serviceid, arg1, arg2 );
2426 else
2427 -> IProfferService_RevokeService( proffer, *arg2 );
2429 init_call_trace(&trace_expected);
2431 add_call(&trace_expected, 1, proff, &IID_IServiceProvider, 0, 0, 0);
2432 add_call(&trace_expected, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2433 add_call(&trace_expected, 3, &dummy_serviceid, provider, &cookie, 0, 0);
2435 init_call_trace(&trace_got);
2436 cookie = 0;
2437 hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, provider, &cookie);
2438 ok(hr == S_OK, "got 0x%08lx\n", hr);
2439 ok(cookie == 0xdeadbeef, "got %lx\n", cookie);
2441 ok_trace(&trace_expected, &trace_got);
2442 free_call_trace(&trace_got);
2443 free_call_trace(&trace_expected);
2445 /* same with ::Revoke path */
2446 init_call_trace(&trace_expected);
2448 add_call(&trace_expected, 1, proff, &IID_IServiceProvider, 0, 0, 0);
2449 add_call(&trace_expected, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2450 add_call(&trace_expected, 4, (void*)(DWORD_PTR)cookie, 0, 0, 0, 0);
2452 init_call_trace(&trace_got);
2453 ok(cookie != 0, "got %lx\n", cookie);
2454 hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, 0, &cookie);
2455 ok(hr == S_OK, "got 0x%08lx\n", hr);
2456 ok(cookie == 0, "got %lx\n", cookie);
2457 ok_trace(&trace_expected, &trace_got);
2458 free_call_trace(&trace_got);
2459 free_call_trace(&trace_expected);
2461 IServiceProvider_Release(provider);
2462 IProfferService_Release(proff);
2465 static void test_SHCreateWorkerWindowA(void)
2467 WNDCLASSA cliA;
2468 char classA[20];
2469 HWND hwnd;
2470 LONG_PTR ret;
2471 BOOL res;
2473 hwnd = pSHCreateWorkerWindowA(0, NULL, 0, 0, 0, 0);
2474 ok(hwnd != 0, "expected window\n");
2476 GetClassNameA(hwnd, classA, 20);
2477 ok(lstrcmpA(classA, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA);
2479 ret = GetWindowLongPtrA(hwnd, 0);
2480 ok(ret == 0, "got %Id\n", ret);
2482 /* class info */
2483 memset(&cliA, 0, sizeof(cliA));
2484 res = GetClassInfoA(GetModuleHandleA("shlwapi.dll"), "WorkerA", &cliA);
2485 ok(res, "failed to get class info\n");
2486 ok(cliA.style == 0, "got 0x%08x\n", cliA.style);
2487 ok(cliA.cbClsExtra == 0, "got %d\n", cliA.cbClsExtra);
2488 ok(cliA.cbWndExtra == sizeof(LONG_PTR), "got %d\n", cliA.cbWndExtra);
2489 ok(cliA.lpszMenuName == 0, "got %s\n", cliA.lpszMenuName);
2491 DestroyWindow(hwnd);
2493 /* set extra bytes */
2494 hwnd = pSHCreateWorkerWindowA(0, NULL, 0, 0, 0, 0xdeadbeef);
2495 ok(hwnd != 0, "expected window\n");
2497 GetClassNameA(hwnd, classA, 20);
2498 ok(lstrcmpA(classA, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA);
2500 ret = GetWindowLongPtrA(hwnd, 0);
2501 ok(ret == 0xdeadbeef, "got %Id\n", ret);
2503 /* test exstyle */
2504 ret = GetWindowLongA(hwnd, GWL_EXSTYLE);
2505 ok(ret == WS_EX_WINDOWEDGE ||
2506 ret == (WS_EX_WINDOWEDGE|WS_EX_LAYOUTRTL) /* systems with RTL locale */, "0x%08Ix\n", ret);
2508 DestroyWindow(hwnd);
2510 hwnd = pSHCreateWorkerWindowA(0, NULL, WS_EX_TOOLWINDOW, 0, 0, 0);
2511 ret = GetWindowLongA(hwnd, GWL_EXSTYLE);
2512 ok(ret == (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW) ||
2513 ret == (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW|WS_EX_LAYOUTRTL) /* systems with RTL locale */, "0x%08Ix\n", ret);
2514 DestroyWindow(hwnd);
2517 static HRESULT WINAPI SF_QueryInterface(IShellFolder *iface,
2518 REFIID riid, void **ppv)
2520 /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */
2521 ok(!IsEqualGUID(&IID_IShellFolder, riid),
2522 "Unexpected QI for IShellFolder\n");
2523 return E_NOINTERFACE;
2526 static ULONG WINAPI SF_AddRef(IShellFolder *iface)
2528 return 2;
2531 static ULONG WINAPI SF_Release(IShellFolder *iface)
2533 return 1;
2536 static HRESULT WINAPI SF_ParseDisplayName(IShellFolder *iface,
2537 HWND owner, LPBC reserved, LPOLESTR displayName, ULONG *eaten,
2538 LPITEMIDLIST *idl, ULONG *attr)
2540 ok(0, "Didn't expect ParseDisplayName\n");
2541 return E_NOTIMPL;
2544 static HRESULT WINAPI SF_EnumObjects(IShellFolder *iface,
2545 HWND owner, SHCONTF flags, IEnumIDList **enm)
2547 *enm = (IEnumIDList*)0xcafebabe;
2548 return S_OK;
2551 static HRESULT WINAPI SF_BindToObject(IShellFolder *iface,
2552 LPCITEMIDLIST idl, LPBC reserved, REFIID riid, void **obj)
2554 ok(0, "Didn't expect BindToObject\n");
2555 return E_NOTIMPL;
2558 static HRESULT WINAPI SF_BindToStorage(IShellFolder *iface,
2559 LPCITEMIDLIST idl, LPBC reserved, REFIID riid, void **obj)
2561 ok(0, "Didn't expect BindToStorage\n");
2562 return E_NOTIMPL;
2565 static HRESULT WINAPI SF_CompareIDs(IShellFolder *iface,
2566 LPARAM lparam, LPCITEMIDLIST idl1, LPCITEMIDLIST idl2)
2568 ok(0, "Didn't expect CompareIDs\n");
2569 return E_NOTIMPL;
2572 static HRESULT WINAPI SF_CreateViewObject(IShellFolder *iface,
2573 HWND owner, REFIID riid, void **out)
2575 ok(0, "Didn't expect CreateViewObject\n");
2576 return E_NOTIMPL;
2579 static HRESULT WINAPI SF_GetAttributesOf(IShellFolder *iface,
2580 UINT cidl, LPCITEMIDLIST *idl, SFGAOF *inOut)
2582 ok(0, "Didn't expect GetAttributesOf\n");
2583 return E_NOTIMPL;
2586 static HRESULT WINAPI SF_GetUIObjectOf(IShellFolder *iface,
2587 HWND owner, UINT cidl, LPCITEMIDLIST *idls, REFIID riid, UINT *inOut,
2588 void **out)
2590 ok(0, "Didn't expect GetUIObjectOf\n");
2591 return E_NOTIMPL;
2594 static HRESULT WINAPI SF_GetDisplayNameOf(IShellFolder *iface,
2595 LPCITEMIDLIST idl, SHGDNF flags, STRRET *name)
2597 ok(0, "Didn't expect GetDisplayNameOf\n");
2598 return E_NOTIMPL;
2601 static HRESULT WINAPI SF_SetNameOf(IShellFolder *iface,
2602 HWND hwnd, LPCITEMIDLIST idl, LPCOLESTR name, SHGDNF flags,
2603 LPITEMIDLIST *idlOut)
2605 ok(0, "Didn't expect SetNameOf\n");
2606 return E_NOTIMPL;
2609 static IShellFolderVtbl ShellFolderVtbl = {
2610 SF_QueryInterface,
2611 SF_AddRef,
2612 SF_Release,
2613 SF_ParseDisplayName,
2614 SF_EnumObjects,
2615 SF_BindToObject,
2616 SF_BindToStorage,
2617 SF_CompareIDs,
2618 SF_CreateViewObject,
2619 SF_GetAttributesOf,
2620 SF_GetUIObjectOf,
2621 SF_GetDisplayNameOf,
2622 SF_SetNameOf
2625 static IShellFolder ShellFolder = { &ShellFolderVtbl };
2627 static void test_SHIShellFolder_EnumObjects(void)
2629 IEnumIDList *enm;
2630 HRESULT hres;
2631 IShellFolder *folder;
2633 if(!pSHIShellFolder_EnumObjects){ /* win7 and later */
2634 win_skip("SHIShellFolder_EnumObjects not available\n");
2635 return;
2638 if(0){
2639 /* NULL object crashes on Windows */
2640 pSHIShellFolder_EnumObjects(NULL, NULL, 0, NULL);
2643 /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */
2644 enm = (IEnumIDList*)0xdeadbeef;
2645 hres = pSHIShellFolder_EnumObjects(&ShellFolder, NULL, 0, &enm);
2646 ok(hres == S_OK, "SHIShellFolder_EnumObjects failed: 0x%08lx\n", hres);
2647 ok(enm == (IEnumIDList*)0xcafebabe, "Didn't get expected enumerator location, instead: %p\n", enm);
2649 /* SHIShellFolder_EnumObjects isn't strict about the IShellFolder object */
2650 hres = SHGetDesktopFolder(&folder);
2651 ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08lx\n", hres);
2653 enm = NULL;
2654 hres = pSHIShellFolder_EnumObjects(folder, NULL, 0, &enm);
2655 ok(hres == S_OK, "SHIShellFolder_EnumObjects failed: 0x%08lx\n", hres);
2656 ok(enm != NULL, "Didn't get an enumerator\n");
2657 if(enm)
2658 IEnumIDList_Release(enm);
2660 IShellFolder_Release(folder);
2663 static BOOL write_inifile(LPCWSTR filename)
2665 DWORD written;
2666 HANDLE file;
2668 static const char data[] =
2669 "[TestApp]\r\n"
2670 "AKey=1\r\n"
2671 "AnotherKey=asdf\r\n";
2673 file = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
2674 if(file == INVALID_HANDLE_VALUE) {
2675 win_skip("failed to create ini file at %s\n", wine_dbgstr_w(filename));
2676 return FALSE;
2679 WriteFile(file, data, sizeof(data), &written, NULL);
2681 CloseHandle(file);
2683 return TRUE;
2686 #define verify_inifile(f, e) r_verify_inifile(__LINE__, f, e)
2687 static void r_verify_inifile(unsigned l, LPCWSTR filename, LPCSTR exp)
2689 HANDLE file;
2690 CHAR buf[1024];
2691 DWORD read;
2693 file = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
2695 if(file == INVALID_HANDLE_VALUE)
2696 return;
2698 ReadFile(file, buf, sizeof(buf) * sizeof(CHAR), &read, NULL);
2699 buf[read] = '\0';
2701 CloseHandle(file);
2703 ok_(__FILE__,l)(!strcmp(buf, exp), "Expected:\n%s\nGot:\n%s\n", exp,
2704 buf);
2707 static void test_SHGetIniString(void)
2709 DWORD ret;
2710 WCHAR out[64] = {0};
2712 static const WCHAR TestAppW[] = {'T','e','s','t','A','p','p',0};
2713 static const WCHAR AKeyW[] = {'A','K','e','y',0};
2714 static const WCHAR AnotherKeyW[] = {'A','n','o','t','h','e','r','K','e','y',0};
2715 static const WCHAR JunkKeyW[] = {'J','u','n','k','K','e','y',0};
2716 static const WCHAR testpathW[] = {'C',':','\\','t','e','s','t','.','i','n','i',0};
2717 WCHAR pathW[MAX_PATH];
2719 lstrcpyW(pathW, testpathW);
2721 if (!write_inifile(pathW))
2722 return;
2724 if(0){
2725 /* these crash on Windows */
2726 pSHGetIniStringW(NULL, NULL, NULL, 0, NULL);
2727 pSHGetIniStringW(NULL, AKeyW, out, ARRAY_SIZE(out), pathW);
2728 pSHGetIniStringW(TestAppW, AKeyW, NULL, ARRAY_SIZE(out), pathW);
2731 ret = pSHGetIniStringW(TestAppW, AKeyW, out, 0, pathW);
2732 ok(ret == 0, "SHGetIniStringW should have given 0, instead: %ld\n", ret);
2734 /* valid arguments */
2735 out[0] = 0;
2736 SetLastError(0xdeadbeef);
2737 ret = pSHGetIniStringW(TestAppW, NULL, out, ARRAY_SIZE(out), pathW);
2738 ok(ret == 4, "SHGetIniStringW should have given 4, instead: %ld\n", ret);
2739 ok(!lstrcmpW(out, AKeyW), "Expected %s, got: %s, %ld\n",
2740 wine_dbgstr_w(AKeyW), wine_dbgstr_w(out), GetLastError());
2742 ret = pSHGetIniStringW(TestAppW, AKeyW, out, ARRAY_SIZE(out), pathW);
2743 ok(ret == 1, "SHGetIniStringW should have given 1, instead: %ld\n", ret);
2744 ok(!lstrcmpW(out, L"1"), "Expected L\"1\", got: %s\n", wine_dbgstr_w(out));
2746 ret = pSHGetIniStringW(TestAppW, AnotherKeyW, out, ARRAY_SIZE(out), pathW);
2747 ok(ret == 4, "SHGetIniStringW should have given 4, instead: %ld\n", ret);
2748 ok(!lstrcmpW(out, L"asdf"), "Expected L\"asdf\", got: %s\n", wine_dbgstr_w(out));
2750 out[0] = 1;
2751 ret = pSHGetIniStringW(TestAppW, JunkKeyW, out, ARRAY_SIZE(out), pathW);
2752 ok(ret == 0, "SHGetIniStringW should have given 0, instead: %ld\n", ret);
2753 ok(*out == 0, "Expected L\"\", got: %s\n", wine_dbgstr_w(out));
2755 DeleteFileW(pathW);
2758 static void test_SHSetIniString(void)
2760 BOOL ret;
2762 static const WCHAR TestAppW[] = {'T','e','s','t','A','p','p',0};
2763 static const WCHAR AnotherAppW[] = {'A','n','o','t','h','e','r','A','p','p',0};
2764 static const WCHAR TestIniW[] = {'C',':','\\','t','e','s','t','.','i','n','i',0};
2765 static const WCHAR AKeyW[] = {'A','K','e','y',0};
2766 static const WCHAR NewKeyW[] = {'N','e','w','K','e','y',0};
2767 static const WCHAR AValueW[] = {'A','V','a','l','u','e',0};
2769 if (!write_inifile(TestIniW))
2770 return;
2772 ret = pSHSetIniStringW(TestAppW, AKeyW, AValueW, TestIniW);
2773 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2774 todo_wine /* wine sticks an extra \r\n at the end of the file */
2775 verify_inifile(TestIniW, "[TestApp]\r\nAKey=AValue\r\nAnotherKey=asdf\r\n");
2777 ret = pSHSetIniStringW(TestAppW, AKeyW, NULL, TestIniW);
2778 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2779 verify_inifile(TestIniW, "[TestApp]\r\nAnotherKey=asdf\r\n");
2781 ret = pSHSetIniStringW(AnotherAppW, NewKeyW, AValueW, TestIniW);
2782 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2783 verify_inifile(TestIniW, "[TestApp]\r\nAnotherKey=asdf\r\n[AnotherApp]\r\nNewKey=AValue\r\n");
2785 ret = pSHSetIniStringW(TestAppW, NULL, AValueW, TestIniW);
2786 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2787 verify_inifile(TestIniW, "[AnotherApp]\r\nNewKey=AValue\r\n");
2789 DeleteFileW(TestIniW);
2792 enum _shellkey_flags {
2793 SHKEY_Root_HKCU = 0x1,
2794 SHKEY_Root_HKLM = 0x2,
2795 SHKEY_Key_Explorer = 0x00,
2796 SHKEY_Key_Shell = 0x10,
2797 SHKEY_Key_ShellNoRoam = 0x20,
2798 SHKEY_Key_Classes = 0x30,
2799 SHKEY_Subkey_Default = 0x0000,
2800 SHKEY_Subkey_ResourceName = 0x1000,
2801 SHKEY_Subkey_Handlers = 0x2000,
2802 SHKEY_Subkey_Associations = 0x3000,
2803 SHKEY_Subkey_Volatile = 0x4000,
2804 SHKEY_Subkey_MUICache = 0x5000,
2805 SHKEY_Subkey_FileExts = 0x6000
2808 static void test_SHGetShellKey(void)
2810 static const WCHAR ShellFoldersW[] = { 'S','h','e','l','l',' ','F','o','l','d','e','r','s',0 };
2811 static const WCHAR WineTestW[] = { 'W','i','n','e','T','e','s','t',0 };
2813 DWORD *alloc_data, data, size;
2814 HKEY hkey;
2815 HRESULT hres;
2817 /* Vista+ limits SHKEY enumeration values */
2818 SetLastError(0xdeadbeef);
2819 hkey = pSHGetShellKey(SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2820 if (hkey)
2822 /* Tests not working on Vista+ */
2823 RegCloseKey(hkey);
2825 hkey = pSHGetShellKey(SHKEY_Root_HKLM|SHKEY_Key_Classes, NULL, FALSE);
2826 ok(hkey != NULL, "hkey = NULL\n");
2827 RegCloseKey(hkey);
2830 hkey = pSHGetShellKey(SHKEY_Root_HKCU|SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2831 ok(hkey != NULL, "hkey = NULL\n");
2832 RegCloseKey(hkey);
2834 hkey = pSHGetShellKey(SHKEY_Root_HKLM|SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2835 ok(hkey != NULL, "hkey = NULL\n");
2836 RegCloseKey(hkey);
2838 hkey = pSHGetShellKey(SHKEY_Root_HKLM, WineTestW, FALSE);
2839 ok(hkey == NULL, "hkey != NULL\n");
2841 hkey = pSHGetShellKey(SHKEY_Root_HKLM, NULL, FALSE);
2842 ok(hkey != NULL, "Can't open key\n");
2843 ok(SUCCEEDED(RegDeleteKeyW(hkey, WineTestW)), "Can't delete key\n");
2844 RegCloseKey(hkey);
2846 hkey = pSHGetShellKey(SHKEY_Root_HKLM, WineTestW, TRUE);
2847 if (!hkey && GetLastError() == ERROR_ACCESS_DENIED)
2849 skip("Not authorized to create keys\n");
2850 return;
2852 ok(hkey != NULL, "Can't create key\n");
2853 RegCloseKey(hkey);
2855 size = sizeof(data);
2856 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
2857 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %lx\n", hres);
2859 data = 1234;
2860 hres = pSKSetValueW(SHKEY_Root_HKLM, WineTestW, NULL, REG_DWORD, &data, sizeof(DWORD));
2861 ok(hres == S_OK, "hres = %lx\n", hres);
2863 size = 1;
2864 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, NULL, &size);
2865 ok(hres == S_OK, "hres = %lx\n", hres);
2866 ok(size == sizeof(DWORD), "size = %ld\n", size);
2868 data = 0xdeadbeef;
2869 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
2870 ok(hres == S_OK, "hres = %lx\n", hres);
2871 ok(size == sizeof(DWORD), "size = %ld\n", size);
2872 ok(data == 1234, "data = %ld\n", data);
2874 hres = pSKAllocValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, (void**)&alloc_data, &size);
2875 ok(hres == S_OK, "hres= %lx\n", hres);
2876 ok(size == sizeof(DWORD), "size = %ld\n", size);
2877 if (SUCCEEDED(hres))
2879 ok(*alloc_data == 1234, "*alloc_data = %ld\n", *alloc_data);
2880 LocalFree(alloc_data);
2883 hres = pSKDeleteValueW(SHKEY_Root_HKLM, WineTestW, NULL);
2884 ok(hres == S_OK, "hres = %lx\n", hres);
2886 hres = pSKDeleteValueW(SHKEY_Root_HKLM, WineTestW, NULL);
2887 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %lx\n", hres);
2889 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
2890 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %lx\n", hres);
2892 hkey = pSHGetShellKey(SHKEY_Root_HKLM, NULL, FALSE);
2893 ok(hkey != NULL, "Can't create key\n");
2894 ok(SUCCEEDED(RegDeleteKeyW(hkey, WineTestW)), "Can't delete key\n");
2895 RegCloseKey(hkey);
2898 static void init_pointers(void)
2900 #define MAKEFUNC(f, ord) (p##f = (void*)GetProcAddress(hShlwapi, (LPSTR)(ord)))
2901 MAKEFUNC(SHAllocShared, 7);
2902 MAKEFUNC(SHLockShared, 8);
2903 MAKEFUNC(SHUnlockShared, 9);
2904 MAKEFUNC(SHFreeShared, 10);
2905 MAKEFUNC(SHMapHandle, 11);
2906 MAKEFUNC(GetAcceptLanguagesA, 14);
2907 MAKEFUNC(SHSetWindowBits, 165);
2908 MAKEFUNC(SHSetParentHwnd, 167);
2909 MAKEFUNC(ConnectToConnectionPoint, 168);
2910 MAKEFUNC(IUnknown_GetClassID, 175);
2911 MAKEFUNC(SHSearchMapInt, 198);
2912 MAKEFUNC(SHCreateWorkerWindowA, 257);
2913 MAKEFUNC(GUIDFromStringA, 269);
2914 MAKEFUNC(SHPackDispParams, 282);
2915 MAKEFUNC(IConnectionPoint_InvokeWithCancel, 283);
2916 MAKEFUNC(IConnectionPoint_SimpleInvoke, 284);
2917 MAKEFUNC(SHGetIniStringW, 294);
2918 MAKEFUNC(SHSetIniStringW, 295);
2919 MAKEFUNC(SHFormatDateTimeA, 353);
2920 MAKEFUNC(SHFormatDateTimeW, 354);
2921 MAKEFUNC(SHIShellFolder_EnumObjects, 404);
2922 MAKEFUNC(GetShellSecurityDescriptor, 475);
2923 MAKEFUNC(SHGetObjectCompatFlags, 476);
2924 MAKEFUNC(IUnknown_QueryServiceExec, 484);
2925 MAKEFUNC(SHGetShellKey, 491);
2926 MAKEFUNC(SHPropertyBag_ReadLONG, 496);
2927 MAKEFUNC(IUnknown_ProfferService, 514);
2928 MAKEFUNC(SKGetValueW, 516);
2929 MAKEFUNC(SKSetValueW, 517);
2930 MAKEFUNC(SKDeleteValueW, 518);
2931 MAKEFUNC(SKAllocValueW, 519);
2932 #undef MAKEFUNC
2934 pDllGetVersion = (void*)GetProcAddress(hShlwapi, "DllGetVersion");
2937 static void test_SHSetParentHwnd(void)
2939 HWND hwnd, hwnd2, ret;
2940 DWORD style;
2942 hwnd = CreateWindowA("Button", "", WS_VISIBLE, 0, 0, 10, 10, NULL, NULL, NULL, NULL);
2943 ok(hwnd != NULL, "got %p\n", hwnd);
2945 hwnd2 = CreateWindowA("Button", "", WS_VISIBLE | WS_CHILD, 0, 0, 10, 10, hwnd, NULL, NULL, NULL);
2946 ok(hwnd2 != NULL, "got %p\n", hwnd2);
2948 /* null params */
2949 ret = pSHSetParentHwnd(NULL, NULL);
2950 ok(ret == NULL, "got %p\n", ret);
2952 /* set to no parent while already no parent present */
2953 ret = GetParent(hwnd);
2954 ok(ret == NULL, "got %p\n", ret);
2955 style = GetWindowLongA(hwnd, GWL_STYLE);
2956 ok((style & (WS_POPUP|WS_CHILD)) == 0, "got style 0x%08lx\n", style);
2957 ret = pSHSetParentHwnd(hwnd, NULL);
2958 ok(ret == NULL, "got %p\n", ret);
2959 style = GetWindowLongA(hwnd, GWL_STYLE);
2960 ok((style & (WS_POPUP|WS_CHILD)) == 0, "got style 0x%08lx\n", style);
2962 /* reset to null parent from not null */
2963 ret = GetParent(hwnd2);
2964 ok(ret == hwnd, "got %p\n", ret);
2965 style = GetWindowLongA(hwnd2, GWL_STYLE);
2966 ok((style & (WS_POPUP|WS_CHILD)) == WS_CHILD, "got style 0x%08lx\n", style);
2967 ret = pSHSetParentHwnd(hwnd2, NULL);
2968 ok(ret == NULL, "got %p\n", ret);
2969 style = GetWindowLongA(hwnd2, GWL_STYLE);
2970 ok((style & (WS_POPUP|WS_CHILD)) == WS_POPUP, "got style 0x%08lx\n", style);
2971 ret = GetParent(hwnd2);
2972 ok(ret == NULL, "got %p\n", ret);
2974 /* set parent back */
2975 style = GetWindowLongA(hwnd2, GWL_STYLE);
2976 SetWindowLongA(hwnd2, GWL_STYLE, style & ~(WS_CHILD|WS_POPUP));
2977 style = GetWindowLongA(hwnd2, GWL_STYLE);
2978 ok((style & (WS_CHILD|WS_POPUP)) == 0, "got 0x%08lx\n", style);
2980 ret = pSHSetParentHwnd(hwnd2, hwnd);
2981 todo_wine ok(ret == NULL, "got %p\n", ret);
2983 style = GetWindowLongA(hwnd2, GWL_STYLE);
2984 ok((style & (WS_POPUP|WS_CHILD)) == WS_CHILD, "got style 0x%08lx\n", style);
2985 ret = GetParent(hwnd2);
2986 ok(ret == hwnd, "got %p\n", ret);
2988 /* try to set same parent again */
2989 /* with WS_POPUP */
2990 style = GetWindowLongA(hwnd2, GWL_STYLE);
2991 SetWindowLongA(hwnd2, GWL_STYLE, style | WS_POPUP);
2992 ret = pSHSetParentHwnd(hwnd2, hwnd);
2993 todo_wine ok(ret == NULL, "got %p\n", ret);
2994 style = GetWindowLongA(hwnd2, GWL_STYLE);
2995 ok((style & (WS_CHILD|WS_POPUP)) == WS_CHILD, "got 0x%08lx\n", style);
2996 ret = GetParent(hwnd2);
2997 ok(ret == hwnd, "got %p\n", ret);
2999 /* without WS_POPUP */
3000 style = GetWindowLongA(hwnd2, GWL_STYLE);
3001 SetWindowLongA(hwnd2, GWL_STYLE, style | ~WS_POPUP);
3002 ret = pSHSetParentHwnd(hwnd2, hwnd);
3003 todo_wine ok(ret == hwnd, "got %p\n", ret);
3004 style = GetWindowLongA(hwnd2, GWL_STYLE);
3005 ok((style & (WS_CHILD|WS_POPUP)) == WS_CHILD, "got 0x%08lx\n", style);
3006 ret = GetParent(hwnd2);
3007 ok(ret == hwnd, "got %p\n", ret);
3009 DestroyWindow(hwnd);
3010 DestroyWindow(hwnd2);
3013 static HRESULT WINAPI testpersist_QI(IPersist *iface, REFIID riid, void **obj)
3015 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPersist)) {
3016 *obj = iface;
3017 IPersist_AddRef(iface);
3018 return S_OK;
3021 *obj = NULL;
3022 return E_NOINTERFACE;
3025 static HRESULT WINAPI testpersist_QI2(IPersist *iface, REFIID riid, void **obj)
3027 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPersistFolder)) {
3028 *obj = iface;
3029 IPersist_AddRef(iface);
3030 return S_OK;
3033 *obj = NULL;
3034 return E_NOINTERFACE;
3037 static ULONG WINAPI testpersist_AddRef(IPersist *iface)
3039 return 2;
3042 static ULONG WINAPI testpersist_Release(IPersist *iface)
3044 return 1;
3047 static HRESULT WINAPI testpersist_GetClassID(IPersist *iface, CLSID *clsid)
3049 memset(clsid, 0xab, sizeof(*clsid));
3050 return 0x8fff2222;
3053 static IPersistVtbl testpersistvtbl = {
3054 testpersist_QI,
3055 testpersist_AddRef,
3056 testpersist_Release,
3057 testpersist_GetClassID
3060 static IPersistVtbl testpersist2vtbl = {
3061 testpersist_QI2,
3062 testpersist_AddRef,
3063 testpersist_Release,
3064 testpersist_GetClassID
3067 static IPersist testpersist = { &testpersistvtbl };
3068 static IPersist testpersist2 = { &testpersist2vtbl };
3070 static void test_IUnknown_GetClassID(void)
3072 CLSID clsid, clsid2, clsid3;
3073 HRESULT hr;
3075 if (0) /* crashes on native systems */
3076 hr = pIUnknown_GetClassID(NULL, NULL);
3078 memset(&clsid, 0xcc, sizeof(clsid));
3079 memset(&clsid3, 0xcc, sizeof(clsid3));
3080 hr = pIUnknown_GetClassID(NULL, &clsid);
3081 ok(hr == E_FAIL, "got 0x%08lx\n", hr);
3082 ok(IsEqualCLSID(&clsid, &CLSID_NULL) || broken(IsEqualCLSID(&clsid, &clsid3)) /* win2k, winxp, win2k3 */,
3083 "got wrong clsid %s\n", wine_dbgstr_guid(&clsid));
3085 memset(&clsid, 0xcc, sizeof(clsid));
3086 memset(&clsid2, 0xab, sizeof(clsid2));
3087 hr = pIUnknown_GetClassID((IUnknown*)&testpersist, &clsid);
3088 ok(hr == 0x8fff2222, "got 0x%08lx\n", hr);
3089 ok(IsEqualCLSID(&clsid, &clsid2) || broken(IsEqualCLSID(&clsid, &clsid3)) /* win2k3 */,
3090 "got wrong clsid %s\n", wine_dbgstr_guid(&clsid));
3092 /* IPersistFolder is also supported */
3093 memset(&clsid, 0xcc, sizeof(clsid));
3094 memset(&clsid2, 0xab, sizeof(clsid2));
3095 memset(&clsid3, 0xcc, sizeof(clsid3));
3096 hr = pIUnknown_GetClassID((IUnknown*)&testpersist2, &clsid);
3097 ok(hr == 0x8fff2222, "got 0x%08lx\n", hr);
3098 ok(IsEqualCLSID(&clsid, &clsid2) || broken(IsEqualCLSID(&clsid, &clsid3)) /* win2k3 */,
3099 "got wrong clsid %s\n", wine_dbgstr_guid(&clsid));
3102 static void test_DllGetVersion(void)
3104 HRESULT hr;
3106 hr = pDllGetVersion(NULL);
3107 ok(hr == E_INVALIDARG, "got 0x%08lx\n", hr);
3110 START_TEST(ordinal)
3112 char **argv;
3113 int argc;
3115 hShlwapi = GetModuleHandleA("shlwapi.dll");
3117 init_pointers();
3119 argc = winetest_get_mainargs(&argv);
3120 if (argc >= 4)
3122 DWORD procid;
3123 HANDLE hmem;
3124 sscanf(argv[2], "%ld", &procid);
3125 sscanf(argv[3], "%p", &hmem);
3126 test_alloc_shared_remote(procid, hmem);
3127 return;
3130 test_GetAcceptLanguagesA();
3131 test_SHSearchMapInt();
3132 test_alloc_shared(argc, argv);
3133 test_fdsa();
3134 test_GetShellSecurityDescriptor();
3135 test_SHPackDispParams();
3136 test_IConnectionPoint();
3137 test_SHPropertyBag_ReadLONG();
3138 test_SHSetWindowBits();
3139 test_SHFormatDateTimeA();
3140 test_SHFormatDateTimeW();
3141 test_SHGetObjectCompatFlags();
3142 test_IUnknown_QueryServiceExec();
3143 test_IUnknown_ProfferService();
3144 test_SHCreateWorkerWindowA();
3145 test_SHIShellFolder_EnumObjects();
3146 test_SHGetIniString();
3147 test_SHSetIniString();
3148 test_SHGetShellKey();
3149 test_SHSetParentHwnd();
3150 test_IUnknown_GetClassID();
3151 test_DllGetVersion();