Remove unnecessary executable bits
[reactos.git] / modules / rostests / winetests / shlwapi / ordinal.c
1 /* Unit test suite for SHLWAPI ordinal functions
2 *
3 * Copyright 2004 Jon Griffiths
4 *
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.
9 *
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.
14 *
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
18 */
19
20 #include <stdio.h>
21
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"
36
37 /* Function ptrs for ordinal calls */
38 static HMODULE hShlwapi;
39
40 static int (WINAPI *pSHSearchMapInt)(const int*,const int*,int,int);
41 static HRESULT (WINAPI *pGetAcceptLanguagesA)(LPSTR,LPDWORD);
42
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*);
72
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 {
79
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;
87
88 static SECURITY_DESCRIPTOR* (WINAPI *pGetShellSecurityDescriptor)(const SHELL_USER_PERMISSION**,int);
89
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};
97
98 static int strcmp_wa(LPCWSTR strw, const char *stra)
99 {
100 CHAR buf[512];
101 WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL);
102 return lstrcmpA(stra, buf);
103 }
104
105 typedef struct {
106 int id;
107 const void *args[5];
108 } call_entry_t;
109
110 typedef struct {
111 call_entry_t *calls;
112 int count;
113 int alloc;
114 } call_trace_t;
115
116 static void init_call_trace(call_trace_t *ctrace)
117 {
118 ctrace->alloc = 10;
119 ctrace->count = 0;
120 ctrace->calls = HeapAlloc(GetProcessHeap(), 0, sizeof(call_entry_t) * ctrace->alloc);
121 }
122
123 static void free_call_trace(const call_trace_t *ctrace)
124 {
125 HeapFree(GetProcessHeap(), 0, ctrace->calls);
126 }
127
128 static void add_call(call_trace_t *ctrace, int id, const void *arg0,
129 const void *arg1, const void *arg2, const void *arg3, const void *arg4)
130 {
131 call_entry_t call;
132
133 call.id = id;
134 call.args[0] = arg0;
135 call.args[1] = arg1;
136 call.args[2] = arg2;
137 call.args[3] = arg3;
138 call.args[4] = arg4;
139
140 if (ctrace->count == ctrace->alloc)
141 {
142 ctrace->alloc *= 2;
143 ctrace->calls = HeapReAlloc(GetProcessHeap(),0, ctrace->calls, ctrace->alloc*sizeof(call_entry_t));
144 }
145
146 ctrace->calls[ctrace->count++] = call;
147 }
148
149 static void ok_trace_(call_trace_t *texpected, call_trace_t *tgot, int line)
150 {
151 if (texpected->count == tgot->count)
152 {
153 INT i;
154 /* compare */
155 for (i = 0; i < texpected->count; i++)
156 {
157 call_entry_t *expected = &texpected->calls[i];
158 call_entry_t *got = &tgot->calls[i];
159 INT j;
160
161 ok_(__FILE__, line)(expected->id == got->id, "got different ids %d: %d, %d\n", i+1, expected->id, got->id);
162
163 for (j = 0; j < 5; j++)
164 {
165 ok_(__FILE__, line)(expected->args[j] == got->args[j], "got different args[%d] for %d: %p, %p\n", j, i+1,
166 expected->args[j], got->args[j]);
167 }
168 }
169 }
170 else
171 ok_(__FILE__, line)(0, "traces length mismatch\n");
172 }
173
174 #define ok_trace(a, b) ok_trace_(a, b, __LINE__)
175
176 /* trace of actually made calls */
177 static call_trace_t trace_got;
178
179 static void test_GetAcceptLanguagesA(void)
180 {
181 static LPCSTR table[] = {"de,en-gb;q=0.7,en;q=0.3",
182 "de,en;q=0.3,en-gb;q=0.7", /* sorting is ignored */
183 "winetest", /* content is ignored */
184 "de-de,de;q=0.5",
185 "de",
186 NULL};
187
188 DWORD exactsize;
189 char original[512];
190 char language[32];
191 char buffer[64];
192 HKEY hroot = NULL;
193 LONG res_query = ERROR_SUCCESS;
194 LONG lres;
195 HRESULT hr;
196 DWORD maxlen = sizeof(buffer) - 2;
197 DWORD len;
198 LCID lcid;
199 LPCSTR entry;
200 INT i = 0;
201
202 lcid = GetUserDefaultLCID();
203
204 /* Get the original Value */
205 lres = RegOpenKeyA(HKEY_CURRENT_USER, ie_international, &hroot);
206 if (lres) {
207 skip("RegOpenKey(%s) failed: %d\n", ie_international, lres);
208 return;
209 }
210 len = sizeof(original);
211 original[0] = 0;
212 res_query = RegQueryValueExA(hroot, acceptlanguage, 0, NULL, (PBYTE)original, &len);
213
214 RegDeleteValueA(hroot, acceptlanguage);
215
216 /* Some windows versions use "lang-COUNTRY" as default */
217 memset(language, 0, sizeof(language));
218 len = GetLocaleInfoA(lcid, LOCALE_SISO639LANGNAME, language, sizeof(language));
219
220 if (len) {
221 lstrcatA(language, "-");
222 memset(buffer, 0, sizeof(buffer));
223 len = GetLocaleInfoA(lcid, LOCALE_SISO3166CTRYNAME, buffer, sizeof(buffer) - len - 1);
224 lstrcatA(language, buffer);
225 }
226 else
227 {
228 /* LOCALE_SNAME has additional parts in some languages. Try only as last chance */
229 memset(language, 0, sizeof(language));
230 len = GetLocaleInfoA(lcid, LOCALE_SNAME, language, sizeof(language));
231 }
232
233 /* get the default value */
234 len = maxlen;
235 memset(buffer, '#', maxlen);
236 buffer[maxlen] = 0;
237 hr = pGetAcceptLanguagesA( buffer, &len);
238
239 if (hr != S_OK) {
240 win_skip("GetAcceptLanguagesA failed with 0x%x\n", hr);
241 goto restore_original;
242 }
243
244 if (lstrcmpA(buffer, language)) {
245 /* some windows versions use "lang" or "lang-country" as default */
246 language[0] = 0;
247 hr = LcidToRfc1766A(lcid, language, sizeof(language));
248 ok(hr == S_OK, "LcidToRfc1766A returned 0x%x and %s\n", hr, language);
249 }
250
251 ok(!lstrcmpA(buffer, language),
252 "have '%s' (searching for '%s')\n", language, buffer);
253
254 if (lstrcmpA(buffer, language)) {
255 win_skip("no more ideas, how to build the default language '%s'\n", buffer);
256 goto restore_original;
257 }
258
259 trace("detected default: %s\n", language);
260 while ((entry = table[i])) {
261
262 exactsize = lstrlenA(entry);
263
264 lres = RegSetValueExA(hroot, acceptlanguage, 0, REG_SZ, (const BYTE *) entry, exactsize + 1);
265 ok(!lres, "got %d for RegSetValueExA: %s\n", lres, entry);
266
267 /* len includes space for the terminating 0 before vista/w2k8 */
268 len = exactsize + 2;
269 memset(buffer, '#', maxlen);
270 buffer[maxlen] = 0;
271 hr = pGetAcceptLanguagesA( buffer, &len);
272 ok(((hr == E_INVALIDARG) && (len == 0)) ||
273 (SUCCEEDED(hr) &&
274 ((len == exactsize) || (len == exactsize+1)) &&
275 !lstrcmpA(buffer, entry)),
276 "+2_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
277
278 len = exactsize + 1;
279 memset(buffer, '#', maxlen);
280 buffer[maxlen] = 0;
281 hr = pGetAcceptLanguagesA( buffer, &len);
282 ok(((hr == E_INVALIDARG) && (len == 0)) ||
283 (SUCCEEDED(hr) &&
284 ((len == exactsize) || (len == exactsize+1)) &&
285 !lstrcmpA(buffer, entry)),
286 "+1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
287
288 len = exactsize;
289 memset(buffer, '#', maxlen);
290 buffer[maxlen] = 0;
291 hr = pGetAcceptLanguagesA( buffer, &len);
292
293 /* There is no space for the string in the registry.
294 When the buffer is large enough, the default language is returned
295
296 When the buffer is too small for that fallback, win7_32 and w2k8_64
297 fail with E_NOT_SUFFICIENT_BUFFER, win8 fails with HRESULT_FROM_WIN32(ERROR_MORE_DATA),
298 other versions succeed and return a partial result while older os succeed
299 and overflow the buffer */
300
301 ok(((hr == E_INVALIDARG) && (len == 0)) ||
302 (((hr == S_OK) && !lstrcmpA(buffer, language) && (len == lstrlenA(language))) ||
303 ((hr == S_OK) && !memcmp(buffer, language, len)) ||
304 ((hr == E_NOT_SUFFICIENT_BUFFER) && !len) ||
305 ((hr == __HRESULT_FROM_WIN32(ERROR_MORE_DATA)) && len == exactsize)),
306 "==_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
307
308 if (exactsize > 1) {
309 len = exactsize - 1;
310 memset(buffer, '#', maxlen);
311 buffer[maxlen] = 0;
312 hr = pGetAcceptLanguagesA( buffer, &len);
313 ok(((hr == E_INVALIDARG) && (len == 0)) ||
314 (((hr == S_OK) && !lstrcmpA(buffer, language) && (len == lstrlenA(language))) ||
315 ((hr == S_OK) && !memcmp(buffer, language, len)) ||
316 ((hr == E_NOT_SUFFICIENT_BUFFER) && !len) ||
317 ((hr == __HRESULT_FROM_WIN32(ERROR_MORE_DATA)) && len == exactsize - 1)),
318 "-1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
319 }
320
321 len = 1;
322 memset(buffer, '#', maxlen);
323 buffer[maxlen] = 0;
324 hr = pGetAcceptLanguagesA( buffer, &len);
325 ok(((hr == E_INVALIDARG) && (len == 0)) ||
326 (((hr == S_OK) && !lstrcmpA(buffer, language) && (len == lstrlenA(language))) ||
327 ((hr == S_OK) && !memcmp(buffer, language, len)) ||
328 ((hr == E_NOT_SUFFICIENT_BUFFER) && !len) ||
329 ((hr == __HRESULT_FROM_WIN32(ERROR_MORE_DATA)) && len == 1)),
330 "=1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
331
332 len = maxlen;
333 hr = pGetAcceptLanguagesA( NULL, &len);
334
335 /* w2k3 and below: E_FAIL and untouched len,
336 since w2k8: S_OK and needed size (excluding 0), win8 S_OK and size including 0. */
337 ok( ((hr == S_OK) && ((len == exactsize) || (len == exactsize + 1))) ||
338 ((hr == E_FAIL) && (len == maxlen)),
339 "NULL,max #%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
340
341 i++;
342 }
343
344 /* without a value in the registry, a default language is returned */
345 RegDeleteValueA(hroot, acceptlanguage);
346
347 len = maxlen;
348 memset(buffer, '#', maxlen);
349 buffer[maxlen] = 0;
350 hr = pGetAcceptLanguagesA( buffer, &len);
351 ok( ((hr == S_OK) && (len == lstrlenA(language))),
352 "max: got 0x%x with %d and %s (expected S_OK with %d and '%s'\n",
353 hr, len, buffer, lstrlenA(language), language);
354
355 len = 2;
356 memset(buffer, '#', maxlen);
357 buffer[maxlen] = 0;
358 hr = pGetAcceptLanguagesA( buffer, &len);
359 ok( (((hr == S_OK) || (hr == E_INVALIDARG)) && !memcmp(buffer, language, len)) ||
360 ((hr == E_NOT_SUFFICIENT_BUFFER) && !len) ||
361 ((hr == __HRESULT_FROM_WIN32(ERROR_CANNOT_COPY)) && !len),
362 "=2: got 0x%x with %d and %s\n", hr, len, buffer);
363
364 len = 1;
365 memset(buffer, '#', maxlen);
366 buffer[maxlen] = 0;
367 hr = pGetAcceptLanguagesA( buffer, &len);
368 /* When the buffer is too small, win7_32 and w2k8_64 and above fail with
369 E_NOT_SUFFICIENT_BUFFER, win8 ERROR_CANNOT_COPY,
370 other versions succeed and return a partial 0 terminated result while other versions
371 fail with E_INVALIDARG and return a partial unterminated result */
372 ok( (((hr == S_OK) || (hr == E_INVALIDARG)) && !memcmp(buffer, language, len)) ||
373 ((hr == E_NOT_SUFFICIENT_BUFFER) && !len) ||
374 ((hr == __HRESULT_FROM_WIN32(ERROR_CANNOT_COPY)) && !len),
375 "=1: got 0x%x with %d and %s\n", hr, len, buffer);
376
377 len = 0;
378 memset(buffer, '#', maxlen);
379 buffer[maxlen] = 0;
380 hr = pGetAcceptLanguagesA( buffer, &len);
381 /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG, win8 ERROR_CANNOT_COPY */
382 ok((hr == E_FAIL) || (hr == E_INVALIDARG) || (hr == __HRESULT_FROM_WIN32(ERROR_CANNOT_COPY)),
383 "got 0x%x\n", hr);
384
385 memset(buffer, '#', maxlen);
386 buffer[maxlen] = 0;
387 hr = pGetAcceptLanguagesA( buffer, NULL);
388 /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG */
389 ok((hr == E_FAIL) || (hr == E_INVALIDARG),
390 "got 0x%x (expected E_FAIL or E_INVALIDARG)\n", hr);
391
392
393 hr = pGetAcceptLanguagesA( NULL, NULL);
394 /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG */
395 ok((hr == E_FAIL) || (hr == E_INVALIDARG),
396 "got 0x%x (expected E_FAIL or E_INVALIDARG)\n", hr);
397
398 restore_original:
399 if (!res_query) {
400 len = lstrlenA(original);
401 lres = RegSetValueExA(hroot, acceptlanguage, 0, REG_SZ, (const BYTE *) original, len ? len + 1: 0);
402 ok(!lres, "RegSetValueEx(%s) failed: %d\n", original, lres);
403 }
404 else
405 {
406 RegDeleteValueA(hroot, acceptlanguage);
407 }
408 RegCloseKey(hroot);
409 }
410
411 static void test_SHSearchMapInt(void)
412 {
413 int keys[8], values[8];
414 int i = 0;
415
416 if (!pSHSearchMapInt)
417 return;
418
419 memset(keys, 0, sizeof(keys));
420 memset(values, 0, sizeof(values));
421 keys[0] = 99; values[0] = 101;
422
423 /* NULL key/value lists crash native, so skip testing them */
424
425 /* 1 element */
426 i = pSHSearchMapInt(keys, values, 1, keys[0]);
427 ok(i == values[0], "Len 1, expected %d, got %d\n", values[0], i);
428
429 /* Key doesn't exist */
430 i = pSHSearchMapInt(keys, values, 1, 100);
431 ok(i == -1, "Len 1 - bad key, expected -1, got %d\n", i);
432
433 /* Len = 0 => not found */
434 i = pSHSearchMapInt(keys, values, 0, keys[0]);
435 ok(i == -1, "Len 1 - passed len 0, expected -1, got %d\n", i);
436
437 /* 2 elements, len = 1 */
438 keys[1] = 98; values[1] = 102;
439 i = pSHSearchMapInt(keys, values, 1, keys[1]);
440 ok(i == -1, "Len 1 - array len 2, expected -1, got %d\n", i);
441
442 /* 2 elements, len = 2 */
443 i = pSHSearchMapInt(keys, values, 2, keys[1]);
444 ok(i == values[1], "Len 2, expected %d, got %d\n", values[1], i);
445
446 /* Searches forward */
447 keys[2] = 99; values[2] = 103;
448 i = pSHSearchMapInt(keys, values, 3, keys[0]);
449 ok(i == values[0], "Len 3, expected %d, got %d\n", values[0], i);
450 }
451
452 struct shared_struct
453 {
454 DWORD value;
455 HANDLE handle;
456 };
457
458 static void test_alloc_shared(int argc, char **argv)
459 {
460 char cmdline[MAX_PATH];
461 PROCESS_INFORMATION pi;
462 STARTUPINFOA si = { 0 };
463 DWORD procid;
464 HANDLE hmem, hmem2 = 0;
465 struct shared_struct val, *p;
466 BOOL ret;
467
468 procid=GetCurrentProcessId();
469 hmem=pSHAllocShared(NULL,10,procid);
470 ok(hmem!=NULL,"SHAllocShared(NULL...) failed: %u\n", GetLastError());
471 ret = pSHFreeShared(hmem, procid);
472 ok( ret, "SHFreeShared failed: %u\n", GetLastError());
473
474 val.value = 0x12345678;
475 val.handle = 0;
476 hmem = pSHAllocShared(&val, sizeof(val), procid);
477 ok(hmem!=NULL,"SHAllocShared(NULL...) failed: %u\n", GetLastError());
478
479 p=pSHLockShared(hmem,procid);
480 ok(p!=NULL,"SHLockShared failed: %u\n", GetLastError());
481 if (p!=NULL)
482 ok(p->value == 0x12345678, "Wrong value in shared memory: %d instead of %d\n", p->value, 0x12345678);
483 ret = pSHUnlockShared(p);
484 ok( ret, "SHUnlockShared failed: %u\n", GetLastError());
485
486 sprintf(cmdline, "%s %s %d %p", argv[0], argv[1], procid, hmem);
487 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
488 ok(ret, "could not create child process error: %u\n", GetLastError());
489 if (ret)
490 {
491 winetest_wait_child_process(pi.hProcess);
492 CloseHandle(pi.hThread);
493 CloseHandle(pi.hProcess);
494
495 p = pSHLockShared(hmem, procid);
496 ok(p != NULL,"SHLockShared failed: %u\n", GetLastError());
497 if (p != NULL && p->value != 0x12345678)
498 {
499 ok(p->value == 0x12345679, "Wrong value in shared memory: %d instead of %d\n", p->value, 0x12345679);
500 hmem2 = p->handle;
501 ok(hmem2 != NULL, "Expected handle in shared memory\n");
502 }
503 ret = pSHUnlockShared(p);
504 ok(ret, "SHUnlockShared failed: %u\n", GetLastError());
505 }
506
507 ret = pSHFreeShared(hmem, procid);
508 ok( ret, "SHFreeShared failed: %u\n", GetLastError());
509
510 if (hmem2)
511 {
512 p = pSHLockShared(hmem2, procid);
513 ok(p != NULL,"SHLockShared failed: %u\n", GetLastError());
514 if (p != NULL)
515 ok(p->value == 0xDEADBEEF, "Wrong value in shared memory: %d instead of %d\n", p->value, 0xDEADBEEF);
516 ret = pSHUnlockShared(p);
517 ok(ret, "SHUnlockShared failed: %u\n", GetLastError());
518
519 ret = pSHFreeShared(hmem2, procid);
520 ok(ret, "SHFreeShared failed: %u\n", GetLastError());
521 }
522
523 SetLastError(0xdeadbeef);
524 ret = pSHFreeShared(NULL, procid);
525 ok(ret, "SHFreeShared failed: %u\n", GetLastError());
526 ok(GetLastError() == 0xdeadbeef, "last error should not have changed, got %u\n", GetLastError());
527 }
528
529 static void test_alloc_shared_remote(DWORD procid, HANDLE hmem)
530 {
531 struct shared_struct val, *p;
532 HANDLE hmem2;
533 BOOL ret;
534
535 /* test directly accessing shared memory of a remote process */
536 p = pSHLockShared(hmem, procid);
537 ok(p != NULL || broken(p == NULL) /* Windows 7/8 */, "SHLockShared failed: %u\n", GetLastError());
538 if (p == NULL)
539 {
540 win_skip("Subprocess failed to modify shared memory, skipping test\n");
541 return;
542 }
543
544 ok(p->value == 0x12345678, "Wrong value in shared memory: %d instead of %d\n", p->value, 0x12345678);
545 p->value++;
546
547 val.value = 0xDEADBEEF;
548 val.handle = 0;
549 p->handle = pSHAllocShared(&val, sizeof(val), procid);
550 ok(p->handle != NULL, "SHAllocShared failed: %u\n", GetLastError());
551
552 ret = pSHUnlockShared(p);
553 ok(ret, "SHUnlockShared failed: %u\n", GetLastError());
554
555 /* test SHMapHandle */
556 SetLastError(0xdeadbeef);
557 hmem2 = pSHMapHandle(NULL, procid, GetCurrentProcessId(), 0, 0);
558 ok(hmem2 == NULL, "expected NULL, got new handle\n");
559 ok(GetLastError() == 0xdeadbeef, "last error should not have changed, got %u\n", GetLastError());
560
561 hmem2 = pSHMapHandle(hmem, procid, GetCurrentProcessId(), 0, 0);
562
563 /* It seems like Windows Vista/2008 uses a different internal implementation
564 * for shared memory, and calling SHMapHandle fails. */
565 ok(hmem2 != NULL || broken(hmem2 == NULL),
566 "SHMapHandle failed: %u\n", GetLastError());
567 if (hmem2 == NULL)
568 {
569 win_skip("Subprocess failed to map shared memory, skipping test\n");
570 return;
571 }
572
573 p = pSHLockShared(hmem2, GetCurrentProcessId());
574 ok(p != NULL, "SHLockShared failed: %u\n", GetLastError());
575
576 if (p != NULL)
577 ok(p->value == 0x12345679, "Wrong value in shared memory: %d instead of %d\n", p->value, 0x12345679);
578
579 ret = pSHUnlockShared(p);
580 ok(ret, "SHUnlockShared failed: %u\n", GetLastError());
581
582 ret = pSHFreeShared(hmem2, GetCurrentProcessId());
583 ok(ret, "SHFreeShared failed: %u\n", GetLastError());
584 }
585
586 static void test_fdsa(void)
587 {
588 typedef struct
589 {
590 DWORD num_items; /* Number of elements inserted */
591 void *mem; /* Ptr to array */
592 DWORD blocks_alloced; /* Number of elements allocated */
593 BYTE inc; /* Number of elements to grow by when we need to expand */
594 BYTE block_size; /* Size in bytes of an element */
595 BYTE flags; /* Flags */
596 } FDSA_info;
597
598 BOOL (WINAPI *pFDSA_Initialize)(DWORD block_size, DWORD inc, FDSA_info *info, void *mem,
599 DWORD init_blocks);
600 BOOL (WINAPI *pFDSA_Destroy)(FDSA_info *info);
601 DWORD (WINAPI *pFDSA_InsertItem)(FDSA_info *info, DWORD where, const void *block);
602 BOOL (WINAPI *pFDSA_DeleteItem)(FDSA_info *info, DWORD where);
603
604 FDSA_info info;
605 int block_size = 10, init_blocks = 4, inc = 2;
606 DWORD ret;
607 char *mem;
608
609 pFDSA_Initialize = (void *)GetProcAddress(hShlwapi, (LPSTR)208);
610 pFDSA_Destroy = (void *)GetProcAddress(hShlwapi, (LPSTR)209);
611 pFDSA_InsertItem = (void *)GetProcAddress(hShlwapi, (LPSTR)210);
612 pFDSA_DeleteItem = (void *)GetProcAddress(hShlwapi, (LPSTR)211);
613
614 mem = HeapAlloc(GetProcessHeap(), 0, block_size * init_blocks);
615 memset(&info, 0, sizeof(info));
616
617 ok(pFDSA_Initialize(block_size, inc, &info, mem, init_blocks), "FDSA_Initialize rets FALSE\n");
618 ok(info.num_items == 0, "num_items = %d\n", info.num_items);
619 ok(info.mem == mem, "mem = %p\n", info.mem);
620 ok(info.blocks_alloced == init_blocks, "blocks_alloced = %d\n", info.blocks_alloced);
621 ok(info.inc == inc, "inc = %d\n", info.inc);
622 ok(info.block_size == block_size, "block_size = %d\n", info.block_size);
623 ok(info.flags == 0, "flags = %d\n", info.flags);
624
625 ret = pFDSA_InsertItem(&info, 1234, "1234567890");
626 ok(ret == 0, "ret = %d\n", ret);
627 ok(info.num_items == 1, "num_items = %d\n", info.num_items);
628 ok(info.mem == mem, "mem = %p\n", info.mem);
629 ok(info.blocks_alloced == init_blocks, "blocks_alloced = %d\n", info.blocks_alloced);
630 ok(info.inc == inc, "inc = %d\n", info.inc);
631 ok(info.block_size == block_size, "block_size = %d\n", info.block_size);
632 ok(info.flags == 0, "flags = %d\n", info.flags);
633
634 ret = pFDSA_InsertItem(&info, 1234, "abcdefghij");
635 ok(ret == 1, "ret = %d\n", ret);
636
637 ret = pFDSA_InsertItem(&info, 1, "klmnopqrst");
638 ok(ret == 1, "ret = %d\n", ret);
639
640 ret = pFDSA_InsertItem(&info, 0, "uvwxyzABCD");
641 ok(ret == 0, "ret = %d\n", ret);
642 ok(info.mem == mem, "mem = %p\n", info.mem);
643 ok(info.flags == 0, "flags = %d\n", info.flags);
644
645 /* This next InsertItem will cause shlwapi to allocate its own mem buffer */
646 ret = pFDSA_InsertItem(&info, 0, "EFGHIJKLMN");
647 ok(ret == 0, "ret = %d\n", ret);
648 ok(info.mem != mem, "mem = %p\n", info.mem);
649 ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %d\n", info.blocks_alloced);
650 ok(info.flags == 0x1, "flags = %d\n", info.flags);
651
652 ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCD1234567890klmnopqrstabcdefghij", 50), "mem %s\n", (char*)info.mem);
653
654 ok(pFDSA_DeleteItem(&info, 2), "rets FALSE\n");
655 ok(info.mem != mem, "mem = %p\n", info.mem);
656 ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %d\n", info.blocks_alloced);
657 ok(info.flags == 0x1, "flags = %d\n", info.flags);
658
659 ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCDklmnopqrstabcdefghij", 40), "mem %s\n", (char*)info.mem);
660
661 ok(pFDSA_DeleteItem(&info, 3), "rets FALSE\n");
662 ok(info.mem != mem, "mem = %p\n", info.mem);
663 ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %d\n", info.blocks_alloced);
664 ok(info.flags == 0x1, "flags = %d\n", info.flags);
665
666 ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCDklmnopqrst", 30), "mem %s\n", (char*)info.mem);
667
668 ok(!pFDSA_DeleteItem(&info, 4), "does not ret FALSE\n");
669
670 /* As shlwapi has allocated memory internally, Destroy will ret FALSE */
671 ok(!pFDSA_Destroy(&info), "FDSA_Destroy does not ret FALSE\n");
672
673
674 /* When Initialize is called with inc = 0, set it to 1 */
675 ok(pFDSA_Initialize(block_size, 0, &info, mem, init_blocks), "FDSA_Initialize rets FALSE\n");
676 ok(info.inc == 1, "inc = %d\n", info.inc);
677
678 /* This time, because shlwapi hasn't had to allocate memory
679 internally, Destroy rets non-zero */
680 ok(pFDSA_Destroy(&info), "FDSA_Destroy rets FALSE\n");
681
682
683 HeapFree(GetProcessHeap(), 0, mem);
684 }
685
686 static void test_GetShellSecurityDescriptor(void)
687 {
688 static const SHELL_USER_PERMISSION supCurrentUserFull = {
689 { {SECURITY_NULL_SID_AUTHORITY}, 0, 0 },
690 ACCESS_ALLOWED_ACE_TYPE, FALSE,
691 GENERIC_ALL, 0, 0 };
692 #define MY_INHERITANCE 0xBE /* invalid value to proof behavior */
693 static const SHELL_USER_PERMISSION supEveryoneDenied = {
694 { {SECURITY_WORLD_SID_AUTHORITY}, SECURITY_WORLD_RID, 0 },
695 ACCESS_DENIED_ACE_TYPE, TRUE,
696 GENERIC_WRITE, MY_INHERITANCE | 0xDEADBA00, GENERIC_READ };
697 const SHELL_USER_PERMISSION* rgsup[2] = {
698 &supCurrentUserFull, &supEveryoneDenied,
699 };
700 SECURITY_DESCRIPTOR* psd;
701
702 if(!pGetShellSecurityDescriptor) /* vista and later */
703 {
704 win_skip("GetShellSecurityDescriptor not available\n");
705 return;
706 }
707
708 psd = pGetShellSecurityDescriptor(NULL, 2);
709 ok(psd==NULL, "GetShellSecurityDescriptor should fail\n");
710 psd = pGetShellSecurityDescriptor(rgsup, 0);
711 ok(psd==NULL, "GetShellSecurityDescriptor should fail, got %p\n", psd);
712
713 SetLastError(0xdeadbeef);
714 psd = pGetShellSecurityDescriptor(rgsup, 2);
715 ok(psd!=NULL, "GetShellSecurityDescriptor failed\n");
716 if (psd!=NULL)
717 {
718 BOOL bHasDacl = FALSE, bDefaulted, ret;
719 PACL pAcl;
720 DWORD dwRev;
721 SECURITY_DESCRIPTOR_CONTROL control;
722
723 ok(IsValidSecurityDescriptor(psd), "returned value is not valid SD\n");
724
725 ret = GetSecurityDescriptorControl(psd, &control, &dwRev);
726 ok(ret, "GetSecurityDescriptorControl failed with error %u\n", GetLastError());
727 ok(0 == (control & SE_SELF_RELATIVE), "SD should be absolute\n");
728
729 ret = GetSecurityDescriptorDacl(psd, &bHasDacl, &pAcl, &bDefaulted);
730 ok(ret, "GetSecurityDescriptorDacl failed with error %u\n", GetLastError());
731
732 ok(bHasDacl, "SD has no DACL\n");
733 if (bHasDacl)
734 {
735 ok(!bDefaulted, "DACL should not be defaulted\n");
736
737 ok(pAcl != NULL, "NULL DACL!\n");
738 if (pAcl != NULL)
739 {
740 ACL_SIZE_INFORMATION asiSize;
741
742 ok(IsValidAcl(pAcl), "DACL is not valid\n");
743
744 ret = GetAclInformation(pAcl, &asiSize, sizeof(asiSize), AclSizeInformation);
745 ok(ret, "GetAclInformation failed with error %u\n", GetLastError());
746
747 ok(asiSize.AceCount == 3, "Incorrect number of ACEs: %d entries\n", asiSize.AceCount);
748 if (asiSize.AceCount == 3)
749 {
750 ACCESS_ALLOWED_ACE *paaa; /* will use for DENIED too */
751
752 ret = GetAce(pAcl, 0, (LPVOID*)&paaa);
753 ok(ret, "GetAce failed with error %u\n", GetLastError());
754 ok(paaa->Header.AceType == ACCESS_ALLOWED_ACE_TYPE,
755 "Invalid ACE type %d\n", paaa->Header.AceType);
756 ok(paaa->Header.AceFlags == 0, "Invalid ACE flags %x\n", paaa->Header.AceFlags);
757 ok(paaa->Mask == GENERIC_ALL, "Invalid ACE mask %x\n", paaa->Mask);
758
759 ret = GetAce(pAcl, 1, (LPVOID*)&paaa);
760 ok(ret, "GetAce failed with error %u\n", GetLastError());
761 ok(paaa->Header.AceType == ACCESS_DENIED_ACE_TYPE,
762 "Invalid ACE type %d\n", paaa->Header.AceType);
763 /* first one of two ACEs generated from inheritable entry - without inheritance */
764 ok(paaa->Header.AceFlags == 0, "Invalid ACE flags %x\n", paaa->Header.AceFlags);
765 ok(paaa->Mask == GENERIC_WRITE, "Invalid ACE mask %x\n", paaa->Mask);
766
767 ret = GetAce(pAcl, 2, (LPVOID*)&paaa);
768 ok(ret, "GetAce failed with error %u\n", GetLastError());
769 ok(paaa->Header.AceType == ACCESS_DENIED_ACE_TYPE,
770 "Invalid ACE type %d\n", paaa->Header.AceType);
771 /* second ACE - with inheritance */
772 ok(paaa->Header.AceFlags == MY_INHERITANCE,
773 "Invalid ACE flags %x\n", paaa->Header.AceFlags);
774 ok(paaa->Mask == GENERIC_READ, "Invalid ACE mask %x\n", paaa->Mask);
775 }
776 }
777 }
778
779 LocalFree(psd);
780 }
781 }
782
783 static void test_SHPackDispParams(void)
784 {
785 DISPPARAMS params;
786 VARIANT vars[10];
787 HRESULT hres;
788
789 memset(&params, 0xc0, sizeof(params));
790 memset(vars, 0xc0, sizeof(vars));
791 hres = pSHPackDispParams(&params, vars, 1, VT_I4, 0xdeadbeef);
792 ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres);
793 ok(params.cArgs == 1, "params.cArgs = %d\n", params.cArgs);
794 ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
795 ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
796 ok(params.rgvarg == vars, "params.rgvarg = %p\n", params.rgvarg);
797 ok(V_VT(vars) == VT_I4, "V_VT(var) = %d\n", V_VT(vars));
798 ok(V_I4(vars) == 0xdeadbeef, "failed %x\n", V_I4(vars));
799
800 memset(&params, 0xc0, sizeof(params));
801 hres = pSHPackDispParams(&params, NULL, 0, 0);
802 ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres);
803 ok(params.cArgs == 0, "params.cArgs = %d\n", params.cArgs);
804 ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
805 ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
806 ok(params.rgvarg == NULL, "params.rgvarg = %p\n", params.rgvarg);
807
808 memset(vars, 0xc0, sizeof(vars));
809 memset(&params, 0xc0, sizeof(params));
810 hres = pSHPackDispParams(&params, vars, 4, VT_BSTR, (void*)0xdeadbeef, VT_EMPTY, 10,
811 VT_I4, 100, VT_DISPATCH, (void*)0xdeadbeef);
812 ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres);
813 ok(params.cArgs == 4, "params.cArgs = %d\n", params.cArgs);
814 ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
815 ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
816 ok(params.rgvarg == vars, "params.rgvarg = %p\n", params.rgvarg);
817 ok(V_VT(vars) == VT_DISPATCH, "V_VT(vars[0]) = %x\n", V_VT(vars));
818 ok(V_I4(vars) == 0xdeadbeef, "V_I4(vars[0]) = %x\n", V_I4(vars));
819 ok(V_VT(vars+1) == VT_I4, "V_VT(vars[1]) = %d\n", V_VT(vars+1));
820 ok(V_I4(vars+1) == 100, "V_I4(vars[1]) = %x\n", V_I4(vars+1));
821 ok(V_VT(vars+2) == VT_I4, "V_VT(vars[2]) = %d\n", V_VT(vars+2));
822 ok(V_I4(vars+2) == 10, "V_I4(vars[2]) = %x\n", V_I4(vars+2));
823 ok(V_VT(vars+3) == VT_BSTR, "V_VT(vars[3]) = %d\n", V_VT(vars+3));
824 ok(V_BSTR(vars+3) == (void*)0xdeadbeef, "V_BSTR(vars[3]) = %p\n", V_BSTR(vars+3));
825 }
826
827 typedef struct _disp
828 {
829 IDispatch IDispatch_iface;
830 LONG refCount;
831 } Disp;
832
833 static inline Disp *impl_from_IDispatch(IDispatch *iface)
834 {
835 return CONTAINING_RECORD(iface, Disp, IDispatch_iface);
836 }
837
838 typedef struct _contain
839 {
840 IConnectionPointContainer IConnectionPointContainer_iface;
841 LONG refCount;
842
843 UINT ptCount;
844 IConnectionPoint **pt;
845 } Contain;
846
847 static inline Contain *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
848 {
849 return CONTAINING_RECORD(iface, Contain, IConnectionPointContainer_iface);
850 }
851
852 typedef struct _cntptn
853 {
854 IConnectionPoint IConnectionPoint_iface;
855 LONG refCount;
856
857 Contain *container;
858 GUID id;
859 UINT sinkCount;
860 IUnknown **sink;
861 } ConPt;
862
863 static inline ConPt *impl_from_IConnectionPoint(IConnectionPoint *iface)
864 {
865 return CONTAINING_RECORD(iface, ConPt, IConnectionPoint_iface);
866 }
867
868 typedef struct _enum
869 {
870 IEnumConnections IEnumConnections_iface;
871 LONG refCount;
872
873 UINT idx;
874 ConPt *pt;
875 } EnumCon;
876
877 static inline EnumCon *impl_from_IEnumConnections(IEnumConnections *iface)
878 {
879 return CONTAINING_RECORD(iface, EnumCon, IEnumConnections_iface);
880 }
881
882 typedef struct _enumpt
883 {
884 IEnumConnectionPoints IEnumConnectionPoints_iface;
885 LONG refCount;
886
887 int idx;
888 Contain *container;
889 } EnumPt;
890
891 static inline EnumPt *impl_from_IEnumConnectionPoints(IEnumConnectionPoints *iface)
892 {
893 return CONTAINING_RECORD(iface, EnumPt, IEnumConnectionPoints_iface);
894 }
895
896
897 static HRESULT WINAPI Disp_QueryInterface(
898 IDispatch* This,
899 REFIID riid,
900 void **ppvObject)
901 {
902 *ppvObject = NULL;
903
904 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDispatch))
905 {
906 *ppvObject = This;
907 }
908
909 if (*ppvObject)
910 {
911 IDispatch_AddRef(This);
912 return S_OK;
913 }
914
915 trace("no interface\n");
916 return E_NOINTERFACE;
917 }
918
919 static ULONG WINAPI Disp_AddRef(IDispatch* This)
920 {
921 Disp *iface = impl_from_IDispatch(This);
922 return InterlockedIncrement(&iface->refCount);
923 }
924
925 static ULONG WINAPI Disp_Release(IDispatch* This)
926 {
927 Disp *iface = impl_from_IDispatch(This);
928 ULONG ret;
929
930 ret = InterlockedDecrement(&iface->refCount);
931 if (ret == 0)
932 HeapFree(GetProcessHeap(),0,This);
933 return ret;
934 }
935
936 static HRESULT WINAPI Disp_GetTypeInfoCount(
937 IDispatch* This,
938 UINT *pctinfo)
939 {
940 return ERROR_SUCCESS;
941 }
942
943 static HRESULT WINAPI Disp_GetTypeInfo(
944 IDispatch* This,
945 UINT iTInfo,
946 LCID lcid,
947 ITypeInfo **ppTInfo)
948 {
949 return ERROR_SUCCESS;
950 }
951
952 static HRESULT WINAPI Disp_GetIDsOfNames(
953 IDispatch* This,
954 REFIID riid,
955 LPOLESTR *rgszNames,
956 UINT cNames,
957 LCID lcid,
958 DISPID *rgDispId)
959 {
960 return ERROR_SUCCESS;
961 }
962
963 static HRESULT WINAPI Disp_Invoke(
964 IDispatch* This,
965 DISPID dispIdMember,
966 REFIID riid,
967 LCID lcid,
968 WORD wFlags,
969 DISPPARAMS *pDispParams,
970 VARIANT *pVarResult,
971 EXCEPINFO *pExcepInfo,
972 UINT *puArgErr)
973 {
974 trace("%p %x %s %x %x %p %p %p %p\n", This, dispIdMember, wine_dbgstr_guid(riid), lcid, wFlags,
975 pDispParams, pVarResult, pExcepInfo, puArgErr);
976
977 ok(dispIdMember == 0xa0 || dispIdMember == 0xa1, "Unknown dispIdMember\n");
978 ok(pDispParams != NULL, "Invoked with NULL pDispParams\n");
979 ok(wFlags == DISPATCH_METHOD, "Wrong flags %x\n",wFlags);
980 ok(lcid == 0,"Wrong lcid %x\n",lcid);
981 if (dispIdMember == 0xa0)
982 {
983 ok(pDispParams->cArgs == 0, "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(pDispParams->rgvarg == NULL, "params.rgvarg = %p\n", pDispParams->rgvarg);
987 }
988 else if (dispIdMember == 0xa1)
989 {
990 ok(pDispParams->cArgs == 2, "params.cArgs = %d\n", pDispParams->cArgs);
991 ok(pDispParams->cNamedArgs == 0, "params.cNamedArgs = %d\n", pDispParams->cArgs);
992 ok(pDispParams->rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", pDispParams->rgdispidNamedArgs);
993 ok(V_VT(pDispParams->rgvarg) == VT_BSTR, "V_VT(var) = %d\n", V_VT(pDispParams->rgvarg));
994 ok(V_I4(pDispParams->rgvarg) == 0xdeadcafe , "failed %p\n", V_BSTR(pDispParams->rgvarg));
995 ok(V_VT(pDispParams->rgvarg+1) == VT_I4, "V_VT(var) = %d\n", V_VT(pDispParams->rgvarg+1));
996 ok(V_I4(pDispParams->rgvarg+1) == 0xdeadbeef, "failed %x\n", V_I4(pDispParams->rgvarg+1));
997 }
998
999 return ERROR_SUCCESS;
1000 }
1001
1002 static const IDispatchVtbl disp_vtbl = {
1003 Disp_QueryInterface,
1004 Disp_AddRef,
1005 Disp_Release,
1006
1007 Disp_GetTypeInfoCount,
1008 Disp_GetTypeInfo,
1009 Disp_GetIDsOfNames,
1010 Disp_Invoke
1011 };
1012
1013 static HRESULT WINAPI Enum_QueryInterface(
1014 IEnumConnections* This,
1015 REFIID riid,
1016 void **ppvObject)
1017 {
1018 *ppvObject = NULL;
1019
1020 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumConnections))
1021 {
1022 *ppvObject = This;
1023 }
1024
1025 if (*ppvObject)
1026 {
1027 IEnumConnections_AddRef(This);
1028 return S_OK;
1029 }
1030
1031 trace("no interface\n");
1032 return E_NOINTERFACE;
1033 }
1034
1035 static ULONG WINAPI Enum_AddRef(IEnumConnections* This)
1036 {
1037 EnumCon *iface = impl_from_IEnumConnections(This);
1038 return InterlockedIncrement(&iface->refCount);
1039 }
1040
1041 static ULONG WINAPI Enum_Release(IEnumConnections* This)
1042 {
1043 EnumCon *iface = impl_from_IEnumConnections(This);
1044 ULONG ret;
1045
1046 ret = InterlockedDecrement(&iface->refCount);
1047 if (ret == 0)
1048 HeapFree(GetProcessHeap(),0,This);
1049 return ret;
1050 }
1051
1052 static HRESULT WINAPI Enum_Next(
1053 IEnumConnections* This,
1054 ULONG cConnections,
1055 LPCONNECTDATA rgcd,
1056 ULONG *pcFetched)
1057 {
1058 EnumCon *iface = impl_from_IEnumConnections(This);
1059
1060 if (cConnections > 0 && iface->idx < iface->pt->sinkCount)
1061 {
1062 rgcd->pUnk = iface->pt->sink[iface->idx];
1063 IUnknown_AddRef(iface->pt->sink[iface->idx]);
1064 rgcd->dwCookie=0xff;
1065 if (pcFetched)
1066 *pcFetched = 1;
1067 iface->idx++;
1068 return S_OK;
1069 }
1070
1071 return E_FAIL;
1072 }
1073
1074 static HRESULT WINAPI Enum_Skip(
1075 IEnumConnections* This,
1076 ULONG cConnections)
1077 {
1078 return E_FAIL;
1079 }
1080
1081 static HRESULT WINAPI Enum_Reset(
1082 IEnumConnections* This)
1083 {
1084 return E_FAIL;
1085 }
1086
1087 static HRESULT WINAPI Enum_Clone(
1088 IEnumConnections* This,
1089 IEnumConnections **ppEnum)
1090 {
1091 return E_FAIL;
1092 }
1093
1094 static const IEnumConnectionsVtbl enum_vtbl = {
1095
1096 Enum_QueryInterface,
1097 Enum_AddRef,
1098 Enum_Release,
1099 Enum_Next,
1100 Enum_Skip,
1101 Enum_Reset,
1102 Enum_Clone
1103 };
1104
1105 static HRESULT WINAPI ConPt_QueryInterface(
1106 IConnectionPoint* This,
1107 REFIID riid,
1108 void **ppvObject)
1109 {
1110 *ppvObject = NULL;
1111
1112 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IConnectionPoint))
1113 {
1114 *ppvObject = This;
1115 }
1116
1117 if (*ppvObject)
1118 {
1119 IConnectionPoint_AddRef(This);
1120 return S_OK;
1121 }
1122
1123 trace("no interface\n");
1124 return E_NOINTERFACE;
1125 }
1126
1127 static ULONG WINAPI ConPt_AddRef(
1128 IConnectionPoint* This)
1129 {
1130 ConPt *iface = impl_from_IConnectionPoint(This);
1131 return InterlockedIncrement(&iface->refCount);
1132 }
1133
1134 static ULONG WINAPI ConPt_Release(
1135 IConnectionPoint* This)
1136 {
1137 ConPt *iface = impl_from_IConnectionPoint(This);
1138 ULONG ret;
1139
1140 ret = InterlockedDecrement(&iface->refCount);
1141 if (ret == 0)
1142 {
1143 if (iface->sinkCount > 0)
1144 {
1145 int i;
1146 for (i = 0; i < iface->sinkCount; i++)
1147 {
1148 if (iface->sink[i])
1149 IUnknown_Release(iface->sink[i]);
1150 }
1151 HeapFree(GetProcessHeap(),0,iface->sink);
1152 }
1153 HeapFree(GetProcessHeap(),0,This);
1154 }
1155 return ret;
1156 }
1157
1158 static HRESULT WINAPI ConPt_GetConnectionInterface(
1159 IConnectionPoint* This,
1160 IID *pIID)
1161 {
1162 static int i = 0;
1163 ConPt *iface = impl_from_IConnectionPoint(This);
1164 if (i==0)
1165 {
1166 i++;
1167 return E_FAIL;
1168 }
1169 else
1170 memcpy(pIID,&iface->id,sizeof(GUID));
1171 return S_OK;
1172 }
1173
1174 static HRESULT WINAPI ConPt_GetConnectionPointContainer(
1175 IConnectionPoint* This,
1176 IConnectionPointContainer **ppCPC)
1177 {
1178 ConPt *iface = impl_from_IConnectionPoint(This);
1179
1180 *ppCPC = &iface->container->IConnectionPointContainer_iface;
1181 return S_OK;
1182 }
1183
1184 static HRESULT WINAPI ConPt_Advise(
1185 IConnectionPoint* This,
1186 IUnknown *pUnkSink,
1187 DWORD *pdwCookie)
1188 {
1189 ConPt *iface = impl_from_IConnectionPoint(This);
1190
1191 if (iface->sinkCount == 0)
1192 iface->sink = HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown*));
1193 else
1194 iface->sink = HeapReAlloc(GetProcessHeap(),0,iface->sink,sizeof(IUnknown*)*(iface->sinkCount+1));
1195 iface->sink[iface->sinkCount] = pUnkSink;
1196 IUnknown_AddRef(pUnkSink);
1197 iface->sinkCount++;
1198 *pdwCookie = iface->sinkCount;
1199 return S_OK;
1200 }
1201
1202 static HRESULT WINAPI ConPt_Unadvise(
1203 IConnectionPoint* This,
1204 DWORD dwCookie)
1205 {
1206 ConPt *iface = impl_from_IConnectionPoint(This);
1207
1208 if (dwCookie > iface->sinkCount)
1209 return E_FAIL;
1210 else
1211 {
1212 IUnknown_Release(iface->sink[dwCookie-1]);
1213 iface->sink[dwCookie-1] = NULL;
1214 }
1215 return S_OK;
1216 }
1217
1218 static HRESULT WINAPI ConPt_EnumConnections(
1219 IConnectionPoint* This,
1220 IEnumConnections **ppEnum)
1221 {
1222 EnumCon *ec;
1223
1224 ec = HeapAlloc(GetProcessHeap(),0,sizeof(EnumCon));
1225 ec->IEnumConnections_iface.lpVtbl = &enum_vtbl;
1226 ec->refCount = 1;
1227 ec->pt = impl_from_IConnectionPoint(This);
1228 ec->idx = 0;
1229 *ppEnum = &ec->IEnumConnections_iface;
1230
1231 return S_OK;
1232 }
1233
1234 static const IConnectionPointVtbl point_vtbl = {
1235 ConPt_QueryInterface,
1236 ConPt_AddRef,
1237 ConPt_Release,
1238
1239 ConPt_GetConnectionInterface,
1240 ConPt_GetConnectionPointContainer,
1241 ConPt_Advise,
1242 ConPt_Unadvise,
1243 ConPt_EnumConnections
1244 };
1245
1246 static HRESULT WINAPI EnumPt_QueryInterface(
1247 IEnumConnectionPoints* This,
1248 REFIID riid,
1249 void **ppvObject)
1250 {
1251 *ppvObject = NULL;
1252
1253 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumConnectionPoints))
1254 {
1255 *ppvObject = This;
1256 }
1257
1258 if (*ppvObject)
1259 {
1260 IEnumConnectionPoints_AddRef(This);
1261 return S_OK;
1262 }
1263
1264 trace("no interface\n");
1265 return E_NOINTERFACE;
1266 }
1267
1268 static ULONG WINAPI EnumPt_AddRef(IEnumConnectionPoints* This)
1269 {
1270 EnumPt *iface = impl_from_IEnumConnectionPoints(This);
1271 return InterlockedIncrement(&iface->refCount);
1272 }
1273
1274 static ULONG WINAPI EnumPt_Release(IEnumConnectionPoints* This)
1275 {
1276 EnumPt *iface = impl_from_IEnumConnectionPoints(This);
1277 ULONG ret;
1278
1279 ret = InterlockedDecrement(&iface->refCount);
1280 if (ret == 0)
1281 HeapFree(GetProcessHeap(),0,This);
1282 return ret;
1283 }
1284
1285 static HRESULT WINAPI EnumPt_Next(
1286 IEnumConnectionPoints* This,
1287 ULONG cConnections,
1288 IConnectionPoint **rgcd,
1289 ULONG *pcFetched)
1290 {
1291 EnumPt *iface = impl_from_IEnumConnectionPoints(This);
1292
1293 if (cConnections > 0 && iface->idx < iface->container->ptCount)
1294 {
1295 *rgcd = iface->container->pt[iface->idx];
1296 IConnectionPoint_AddRef(iface->container->pt[iface->idx]);
1297 if (pcFetched)
1298 *pcFetched = 1;
1299 iface->idx++;
1300 return S_OK;
1301 }
1302
1303 return E_FAIL;
1304 }
1305
1306 static HRESULT WINAPI EnumPt_Skip(
1307 IEnumConnectionPoints* This,
1308 ULONG cConnections)
1309 {
1310 return E_FAIL;
1311 }
1312
1313 static HRESULT WINAPI EnumPt_Reset(
1314 IEnumConnectionPoints* This)
1315 {
1316 return E_FAIL;
1317 }
1318
1319 static HRESULT WINAPI EnumPt_Clone(
1320 IEnumConnectionPoints* This,
1321 IEnumConnectionPoints **ppEnumPt)
1322 {
1323 return E_FAIL;
1324 }
1325
1326 static const IEnumConnectionPointsVtbl enumpt_vtbl = {
1327
1328 EnumPt_QueryInterface,
1329 EnumPt_AddRef,
1330 EnumPt_Release,
1331 EnumPt_Next,
1332 EnumPt_Skip,
1333 EnumPt_Reset,
1334 EnumPt_Clone
1335 };
1336
1337 static HRESULT WINAPI Contain_QueryInterface(
1338 IConnectionPointContainer* This,
1339 REFIID riid,
1340 void **ppvObject)
1341 {
1342 *ppvObject = NULL;
1343
1344 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IConnectionPointContainer))
1345 {
1346 *ppvObject = This;
1347 }
1348
1349 if (*ppvObject)
1350 {
1351 IConnectionPointContainer_AddRef(This);
1352 return S_OK;
1353 }
1354
1355 trace("no interface\n");
1356 return E_NOINTERFACE;
1357 }
1358
1359 static ULONG WINAPI Contain_AddRef(
1360 IConnectionPointContainer* This)
1361 {
1362 Contain *iface = impl_from_IConnectionPointContainer(This);
1363 return InterlockedIncrement(&iface->refCount);
1364 }
1365
1366 static ULONG WINAPI Contain_Release(
1367 IConnectionPointContainer* This)
1368 {
1369 Contain *iface = impl_from_IConnectionPointContainer(This);
1370 ULONG ret;
1371
1372 ret = InterlockedDecrement(&iface->refCount);
1373 if (ret == 0)
1374 {
1375 if (iface->ptCount > 0)
1376 {
1377 int i;
1378 for (i = 0; i < iface->ptCount; i++)
1379 IConnectionPoint_Release(iface->pt[i]);
1380 HeapFree(GetProcessHeap(),0,iface->pt);
1381 }
1382 HeapFree(GetProcessHeap(),0,This);
1383 }
1384 return ret;
1385 }
1386
1387 static HRESULT WINAPI Contain_EnumConnectionPoints(
1388 IConnectionPointContainer* This,
1389 IEnumConnectionPoints **ppEnum)
1390 {
1391 EnumPt *ec;
1392
1393 ec = HeapAlloc(GetProcessHeap(),0,sizeof(EnumPt));
1394 ec->IEnumConnectionPoints_iface.lpVtbl = &enumpt_vtbl;
1395 ec->refCount = 1;
1396 ec->idx= 0;
1397 ec->container = impl_from_IConnectionPointContainer(This);
1398 *ppEnum = &ec->IEnumConnectionPoints_iface;
1399
1400 return S_OK;
1401 }
1402
1403 static HRESULT WINAPI Contain_FindConnectionPoint(
1404 IConnectionPointContainer* This,
1405 REFIID riid,
1406 IConnectionPoint **ppCP)
1407 {
1408 Contain *iface = impl_from_IConnectionPointContainer(This);
1409 ConPt *pt;
1410
1411 if (!IsEqualIID(riid, &IID_NULL) || iface->ptCount ==0)
1412 {
1413 pt = HeapAlloc(GetProcessHeap(),0,sizeof(ConPt));
1414 pt->IConnectionPoint_iface.lpVtbl = &point_vtbl;
1415 pt->refCount = 1;
1416 pt->sinkCount = 0;
1417 pt->sink = NULL;
1418 pt->container = iface;
1419 pt->id = IID_IDispatch;
1420
1421 if (iface->ptCount == 0)
1422 iface->pt =HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown*));
1423 else
1424 iface->pt = HeapReAlloc(GetProcessHeap(),0,iface->pt,sizeof(IUnknown*)*(iface->ptCount+1));
1425 iface->pt[iface->ptCount] = &pt->IConnectionPoint_iface;
1426 iface->ptCount++;
1427
1428 *ppCP = &pt->IConnectionPoint_iface;
1429 }
1430 else
1431 {
1432 *ppCP = iface->pt[0];
1433 IUnknown_AddRef((IUnknown*)*ppCP);
1434 }
1435
1436 return S_OK;
1437 }
1438
1439 static const IConnectionPointContainerVtbl contain_vtbl = {
1440 Contain_QueryInterface,
1441 Contain_AddRef,
1442 Contain_Release,
1443
1444 Contain_EnumConnectionPoints,
1445 Contain_FindConnectionPoint
1446 };
1447
1448 static void test_IConnectionPoint(void)
1449 {
1450 HRESULT rc;
1451 ULONG ref;
1452 IConnectionPoint *point;
1453 Contain *container;
1454 Disp *dispatch;
1455 DWORD cookie = 0xffffffff;
1456 DISPPARAMS params;
1457 VARIANT vars[10];
1458
1459 container = HeapAlloc(GetProcessHeap(),0,sizeof(Contain));
1460 container->IConnectionPointContainer_iface.lpVtbl = &contain_vtbl;
1461 container->refCount = 1;
1462 container->ptCount = 0;
1463 container->pt = NULL;
1464
1465 dispatch = HeapAlloc(GetProcessHeap(),0,sizeof(Disp));
1466 dispatch->IDispatch_iface.lpVtbl = &disp_vtbl;
1467 dispatch->refCount = 1;
1468
1469 rc = pConnectToConnectionPoint((IUnknown*)dispatch, &IID_NULL, TRUE, (IUnknown*)container, &cookie, &point);
1470 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1471 ok(point != NULL, "returned ConnectionPoint is NULL\n");
1472 ok(cookie != 0xffffffff, "invalid cookie returned\n");
1473
1474 rc = pIConnectionPoint_SimpleInvoke(point,0xa0,NULL);
1475 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1476
1477 memset(&params, 0xc0, sizeof(params));
1478 memset(vars, 0xc0, sizeof(vars));
1479 rc = pSHPackDispParams(&params, vars, 2, VT_I4, 0xdeadbeef, VT_BSTR, 0xdeadcafe);
1480 ok(rc == S_OK, "SHPackDispParams failed: %08x\n", rc);
1481
1482 rc = pIConnectionPoint_SimpleInvoke(point,0xa1,&params);
1483 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1484
1485 rc = pConnectToConnectionPoint(NULL, &IID_NULL, FALSE, (IUnknown*)container, &cookie, NULL);
1486 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1487
1488 /* MSDN says this should be required but it crashs on XP
1489 IUnknown_Release(point);
1490 */
1491 ref = IUnknown_Release((IUnknown*)container);
1492 ok(ref == 0, "leftover IConnectionPointContainer reference %i\n",ref);
1493 ref = IUnknown_Release((IUnknown*)dispatch);
1494 ok(ref == 0, "leftover IDispatch reference %i\n",ref);
1495 }
1496
1497 typedef struct _propbag
1498 {
1499 IPropertyBag IPropertyBag_iface;
1500 LONG refCount;
1501
1502 } PropBag;
1503
1504 static inline PropBag *impl_from_IPropertyBag(IPropertyBag *iface)
1505 {
1506 return CONTAINING_RECORD(iface, PropBag, IPropertyBag_iface);
1507 }
1508
1509
1510 static HRESULT WINAPI Prop_QueryInterface(
1511 IPropertyBag* This,
1512 REFIID riid,
1513 void **ppvObject)
1514 {
1515 *ppvObject = NULL;
1516
1517 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPropertyBag))
1518 {
1519 *ppvObject = This;
1520 }
1521
1522 if (*ppvObject)
1523 {
1524 IPropertyBag_AddRef(This);
1525 return S_OK;
1526 }
1527
1528 trace("no interface\n");
1529 return E_NOINTERFACE;
1530 }
1531
1532 static ULONG WINAPI Prop_AddRef(
1533 IPropertyBag* This)
1534 {
1535 PropBag *iface = impl_from_IPropertyBag(This);
1536 return InterlockedIncrement(&iface->refCount);
1537 }
1538
1539 static ULONG WINAPI Prop_Release(
1540 IPropertyBag* This)
1541 {
1542 PropBag *iface = impl_from_IPropertyBag(This);
1543 ULONG ret;
1544
1545 ret = InterlockedDecrement(&iface->refCount);
1546 if (ret == 0)
1547 HeapFree(GetProcessHeap(),0,This);
1548 return ret;
1549 }
1550
1551 static HRESULT WINAPI Prop_Read(
1552 IPropertyBag* This,
1553 LPCOLESTR pszPropName,
1554 VARIANT *pVar,
1555 IErrorLog *pErrorLog)
1556 {
1557 V_VT(pVar) = VT_BLOB|VT_BYREF;
1558 V_BYREF(pVar) = (LPVOID)0xdeadcafe;
1559 return S_OK;
1560 }
1561
1562 static HRESULT WINAPI Prop_Write(
1563 IPropertyBag* This,
1564 LPCOLESTR pszPropName,
1565 VARIANT *pVar)
1566 {
1567 return S_OK;
1568 }
1569
1570
1571 static const IPropertyBagVtbl prop_vtbl = {
1572 Prop_QueryInterface,
1573 Prop_AddRef,
1574 Prop_Release,
1575
1576 Prop_Read,
1577 Prop_Write
1578 };
1579
1580 static void test_SHPropertyBag_ReadLONG(void)
1581 {
1582 PropBag *pb;
1583 HRESULT rc;
1584 LONG out;
1585 static const WCHAR szName1[] = {'n','a','m','e','1',0};
1586
1587 pb = HeapAlloc(GetProcessHeap(),0,sizeof(PropBag));
1588 pb->refCount = 1;
1589 pb->IPropertyBag_iface.lpVtbl = &prop_vtbl;
1590
1591 out = 0xfeedface;
1592 rc = pSHPropertyBag_ReadLONG(NULL, szName1, &out);
1593 ok(rc == E_INVALIDARG || broken(rc == S_OK), "incorrect return %x\n",rc);
1594 ok(out == 0xfeedface, "value should not have changed\n");
1595 rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, NULL, &out);
1596 ok(rc == E_INVALIDARG || broken(rc == S_OK) || broken(rc == S_FALSE), "incorrect return %x\n",rc);
1597 ok(out == 0xfeedface, "value should not have changed\n");
1598 rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, szName1, NULL);
1599 ok(rc == E_INVALIDARG || broken(rc == S_OK) || broken(rc == S_FALSE), "incorrect return %x\n",rc);
1600 rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, szName1, &out);
1601 ok(rc == DISP_E_BADVARTYPE || broken(rc == S_OK) || broken(rc == S_FALSE), "incorrect return %x\n",rc);
1602 ok(out == 0xfeedface || broken(out == 0xfeedfa00), "value should not have changed %x\n",out);
1603 IUnknown_Release((IUnknown*)pb);
1604 }
1605
1606 static void test_SHSetWindowBits(void)
1607 {
1608 HWND hwnd;
1609 DWORD style, styleold;
1610 WNDCLASSA clsA;
1611
1612 clsA.style = 0;
1613 clsA.lpfnWndProc = DefWindowProcA;
1614 clsA.cbClsExtra = 0;
1615 clsA.cbWndExtra = 0;
1616 clsA.hInstance = GetModuleHandleA(NULL);
1617 clsA.hIcon = 0;
1618 clsA.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
1619 clsA.hbrBackground = NULL;
1620 clsA.lpszMenuName = NULL;
1621 clsA.lpszClassName = "Shlwapi test class";
1622 RegisterClassA(&clsA);
1623
1624 hwnd = CreateWindowA("Shlwapi test class", "Test", WS_VISIBLE, 0, 0, 100, 100,
1625 NULL, NULL, GetModuleHandleA(NULL), 0);
1626 ok(IsWindow(hwnd), "failed to create window\n");
1627
1628 /* null window */
1629 SetLastError(0xdeadbeef);
1630 style = pSHSetWindowBits(NULL, GWL_STYLE, 0, 0);
1631 ok(style == 0, "expected 0 retval, got %d\n", style);
1632 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE,
1633 "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
1634
1635 /* zero mask, zero flags */
1636 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1637 style = pSHSetWindowBits(hwnd, GWL_STYLE, 0, 0);
1638 ok(styleold == style, "expected old style\n");
1639 ok(styleold == GetWindowLongA(hwnd, GWL_STYLE), "expected to keep old style\n");
1640
1641 /* test mask */
1642 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1643 ok(styleold & WS_VISIBLE, "expected WS_VISIBLE\n");
1644 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1645
1646 ok(style == styleold, "expected previous style, got %x\n", style);
1647 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1648
1649 /* test mask, unset style bit used */
1650 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1651 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1652 ok(style == styleold, "expected previous style, got %x\n", style);
1653 ok(styleold == GetWindowLongA(hwnd, GWL_STYLE), "expected to keep old style\n");
1654
1655 /* set back with flags */
1656 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1657 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, WS_VISIBLE);
1658 ok(style == styleold, "expected previous style, got %x\n", style);
1659 ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "expected updated style\n");
1660
1661 /* reset and try to set without a mask */
1662 pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1663 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1664 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1665 style = pSHSetWindowBits(hwnd, GWL_STYLE, 0, WS_VISIBLE);
1666 ok(style == styleold, "expected previous style, got %x\n", style);
1667 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1668
1669 DestroyWindow(hwnd);
1670
1671 UnregisterClassA("Shlwapi test class", GetModuleHandleA(NULL));
1672 }
1673
1674 static void test_SHFormatDateTimeA(void)
1675 {
1676 FILETIME UNALIGNED filetime;
1677 CHAR buff[100], buff2[100], buff3[100];
1678 SYSTEMTIME st;
1679 DWORD flags;
1680 INT ret;
1681
1682 if (0)
1683 {
1684 /* crashes on native */
1685 pSHFormatDateTimeA(NULL, NULL, NULL, 0);
1686 }
1687
1688 GetLocalTime(&st);
1689 SystemTimeToFileTime(&st, &filetime);
1690 /* SHFormatDateTime expects input as utc */
1691 LocalFileTimeToFileTime(&filetime, &filetime);
1692
1693 /* no way to get required buffer length here */
1694 SetLastError(0xdeadbeef);
1695 ret = pSHFormatDateTimeA(&filetime, NULL, NULL, 0);
1696 ok(ret == 0, "got %d\n", ret);
1697 ok(GetLastError() == 0xdeadbeef || broken(GetLastError() == ERROR_SUCCESS /* Win7 */),
1698 "expected 0xdeadbeef, got %d\n", GetLastError());
1699
1700 SetLastError(0xdeadbeef);
1701 buff[0] = 'a'; buff[1] = 0;
1702 ret = pSHFormatDateTimeA(&filetime, NULL, buff, 0);
1703 ok(ret == 0, "got %d\n", ret);
1704 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1705 ok(buff[0] == 'a', "expected same string, got %s\n", buff);
1706
1707 /* flags needs to have FDTF_NOAUTOREADINGORDER for these tests to succeed on Vista+ */
1708
1709 /* all combinations documented as invalid succeeded */
1710 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTTIME | FDTF_LONGTIME;
1711 SetLastError(0xdeadbeef);
1712 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1713 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1714 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1715
1716 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_LONGDATE;
1717 SetLastError(0xdeadbeef);
1718 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1719 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1720 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1721
1722 flags = FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE;
1723 SetLastError(0xdeadbeef);
1724 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1725 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1726 ok(GetLastError() == 0xdeadbeef,
1727 "expected 0xdeadbeef, got %d\n", GetLastError());
1728
1729 /* now check returned strings */
1730 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTTIME;
1731 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1732 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1733 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff2, sizeof(buff2));
1734 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1735 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1736
1737 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGTIME;
1738 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1739 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1740 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2));
1741 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1742 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1743
1744 /* both time flags */
1745 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGTIME | FDTF_SHORTTIME;
1746 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1747 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1748 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2));
1749 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1750 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1751
1752 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE;
1753 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1754 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1755 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1756 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1757 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1758
1759 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE;
1760 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1761 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1762 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1763 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1764 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1765
1766 /* both date flags */
1767 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_SHORTDATE;
1768 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1769 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1770 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1771 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1772 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1773
1774 /* various combinations of date/time flags */
1775 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_SHORTTIME;
1776 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1777 ok(ret == lstrlenA(buff)+1, "got %d, length %d\n", ret, lstrlenA(buff)+1);
1778 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3));
1779 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1780 ok(lstrcmpA(buff3, buff + lstrlenA(buff) - lstrlenA(buff3)) == 0,
1781 "expected (%s), got (%s) for time part\n",
1782 buff3, buff + lstrlenA(buff) - lstrlenA(buff3));
1783 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1784 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1785 buff[lstrlenA(buff2)] = '\0';
1786 ok(lstrcmpA(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1787 buff2, buff);
1788
1789 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_LONGTIME;
1790 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1791 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1792 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3));
1793 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1794 ok(lstrcmpA(buff3, buff + lstrlenA(buff) - lstrlenA(buff3)) == 0,
1795 "expected (%s), got (%s) for time part\n",
1796 buff3, buff + lstrlenA(buff) - lstrlenA(buff3));
1797 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1798 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1799 buff[lstrlenA(buff2)] = '\0';
1800 ok(lstrcmpA(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1801 buff2, buff);
1802
1803 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_SHORTTIME;
1804 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1805 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1806 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1807 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1808 strcat(buff2, " ");
1809 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3));
1810 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1811 strcat(buff2, buff3);
1812 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1813
1814 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_LONGTIME;
1815 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1816 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1817 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1818 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1819 strcat(buff2, " ");
1820 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3));
1821 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1822 strcat(buff2, buff3);
1823 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1824 }
1825
1826 static void test_SHFormatDateTimeW(void)
1827 {
1828 FILETIME UNALIGNED filetime;
1829 WCHAR buff[100], buff2[100], buff3[100], *p1, *p2;
1830 SYSTEMTIME st;
1831 DWORD flags;
1832 INT ret;
1833 static const WCHAR spaceW[] = {' ',0};
1834 #define UNICODE_LTR_MARK 0x200e
1835 #define UNICODE_RTL_MARK 0x200f
1836
1837 if (0)
1838 {
1839 /* crashes on native */
1840 pSHFormatDateTimeW(NULL, NULL, NULL, 0);
1841 }
1842
1843 GetLocalTime(&st);
1844 SystemTimeToFileTime(&st, &filetime);
1845 /* SHFormatDateTime expects input as utc */
1846 LocalFileTimeToFileTime(&filetime, &filetime);
1847
1848 /* no way to get required buffer length here */
1849 SetLastError(0xdeadbeef);
1850 ret = pSHFormatDateTimeW(&filetime, NULL, NULL, 0);
1851 ok(ret == 0, "expected 0, got %d\n", ret);
1852 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1853
1854 SetLastError(0xdeadbeef);
1855 buff[0] = 'a'; buff[1] = 0;
1856 ret = pSHFormatDateTimeW(&filetime, NULL, buff, 0);
1857 ok(ret == 0, "expected 0, got %d\n", ret);
1858 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1859 ok(buff[0] == 'a', "expected same string\n");
1860
1861 /* all combinations documented as invalid succeeded */
1862 flags = FDTF_SHORTTIME | FDTF_LONGTIME;
1863 SetLastError(0xdeadbeef);
1864 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1865 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1866 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1867 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1868
1869 flags = FDTF_SHORTDATE | FDTF_LONGDATE;
1870 SetLastError(0xdeadbeef);
1871 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1872 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1873 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1874 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1875
1876 flags = FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE;
1877 SetLastError(0xdeadbeef);
1878 buff[0] = 0; /* NT4 doesn't clear the buffer on failure */
1879 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1880 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1881 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1882 ok(GetLastError() == 0xdeadbeef,
1883 "expected 0xdeadbeef, got %d\n", GetLastError());
1884
1885 /* now check returned strings */
1886 flags = FDTF_SHORTTIME;
1887 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1888 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1889 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1890 SetLastError(0xdeadbeef);
1891 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1892 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1893 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1894
1895 flags = FDTF_LONGTIME;
1896 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1897 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1898 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1899 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1900 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1901 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1902
1903 /* both time flags */
1904 flags = FDTF_LONGTIME | FDTF_SHORTTIME;
1905 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1906 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1907 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1908 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1909 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1910 ok(lstrcmpW(buff, buff2) == 0, "expected equal string\n");
1911
1912 flags = FDTF_SHORTDATE;
1913 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1914 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1915 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1916 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1917 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1918 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1919
1920 flags = FDTF_LONGDATE;
1921 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1922 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1923 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1924 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1925 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1926 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1927
1928 /* both date flags */
1929 flags = FDTF_LONGDATE | FDTF_SHORTDATE;
1930 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1931 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1932 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1933 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1934 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1935 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1936
1937 /* various combinations of date/time flags */
1938 flags = FDTF_LONGDATE | FDTF_SHORTTIME;
1939 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1940 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1941 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1942 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1943 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1944 ok(lstrcmpW(buff3, buff + lstrlenW(buff) - lstrlenW(buff3)) == 0,
1945 "expected (%s), got (%s) for time part\n",
1946 wine_dbgstr_w(buff3), wine_dbgstr_w(buff + lstrlenW(buff) - lstrlenW(buff3)));
1947 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1948 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1949 p1 = buff;
1950 p2 = buff2;
1951 while (*p2 != '\0')
1952 {
1953 while (*p1 == UNICODE_LTR_MARK || *p1 == UNICODE_RTL_MARK)
1954 p1++;
1955 while (*p2 == UNICODE_LTR_MARK || *p2 == UNICODE_RTL_MARK)
1956 p2++;
1957 p1++;
1958 p2++;
1959 }
1960 *p1 = '\0';
1961 ok(lstrcmpW(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1962 wine_dbgstr_w(buff2), wine_dbgstr_w(buff));
1963
1964 flags = FDTF_LONGDATE | FDTF_LONGTIME;
1965 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1966 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1967 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1968 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1969 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1970 ok(lstrcmpW(buff3, buff + lstrlenW(buff) - lstrlenW(buff3)) == 0,
1971 "expected (%s), got (%s) for time part\n",
1972 wine_dbgstr_w(buff3), wine_dbgstr_w(buff + lstrlenW(buff) - lstrlenW(buff3)));
1973 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1974 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1975 p1 = buff;
1976 p2 = buff2;
1977 while (*p2 != '\0')
1978 {
1979 while (*p1 == UNICODE_LTR_MARK || *p1 == UNICODE_RTL_MARK)
1980 p1++;
1981 while (*p2 == UNICODE_LTR_MARK || *p2 == UNICODE_RTL_MARK)
1982 p2++;
1983 p1++;
1984 p2++;
1985 }
1986 *p1 = '\0';
1987 ok(lstrcmpW(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1988 wine_dbgstr_w(buff2), wine_dbgstr_w(buff));
1989
1990 flags = FDTF_SHORTDATE | FDTF_SHORTTIME;
1991 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1992 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1993 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1994 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1995 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1996 lstrcatW(buff2, spaceW);
1997 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1998 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1999 lstrcatW(buff2, buff3);
2000 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
2001
2002 flags = FDTF_SHORTDATE | FDTF_LONGTIME;
2003 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
2004 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
2005 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
2006 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
2007 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
2008 lstrcatW(buff2, spaceW);
2009 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
2010 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
2011 lstrcatW(buff2, buff3);
2012 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
2013 }
2014
2015 static void test_SHGetObjectCompatFlags(void)
2016 {
2017 struct compat_value {
2018 CHAR nameA[30];
2019 DWORD value;
2020 };
2021
2022 struct compat_value values[] = {
2023 { "OTNEEDSSFCACHE", 0x1 },
2024 { "NO_WEBVIEW", 0x2 },
2025 { "UNBINDABLE", 0x4 },
2026 { "PINDLL", 0x8 },
2027 { "NEEDSFILESYSANCESTOR", 0x10 },
2028 { "NOTAFILESYSTEM", 0x20 },
2029 { "CTXMENU_NOVERBS", 0x40 },
2030 { "CTXMENU_LIMITEDQI", 0x80 },
2031 { "COCREATESHELLFOLDERONLY", 0x100 },
2032 { "NEEDSSTORAGEANCESTOR", 0x200 },
2033 { "NOLEGACYWEBVIEW", 0x400 },
2034 { "CTXMENU_XPQCMFLAGS", 0x1000 },
2035 { "NOIPROPERTYSTORE", 0x2000 }
2036 };
2037
2038 static const char compat_path[] = "Software\\Microsoft\\Windows\\CurrentVersion\\ShellCompatibility\\Objects";
2039 CHAR keyA[39]; /* {CLSID} */
2040 HKEY root;
2041 DWORD ret;
2042 int i;
2043
2044 /* null args */
2045 ret = pSHGetObjectCompatFlags(NULL, NULL);
2046 ok(ret == 0, "got %d\n", ret);
2047
2048 ret = RegOpenKeyA(HKEY_LOCAL_MACHINE, compat_path, &root);
2049 if (ret != ERROR_SUCCESS)
2050 {
2051 skip("No compatibility class data found\n");
2052 return;
2053 }
2054
2055 for (i = 0; RegEnumKeyA(root, i, keyA, sizeof(keyA)) == ERROR_SUCCESS; i++)
2056 {
2057 HKEY clsid_key;
2058
2059 if (RegOpenKeyA(root, keyA, &clsid_key) == ERROR_SUCCESS)
2060 {
2061 CHAR valueA[30];
2062 DWORD expected = 0, got, length = sizeof(valueA);
2063 CLSID clsid;
2064 int v;
2065
2066 for (v = 0; RegEnumValueA(clsid_key, v, valueA, &length, NULL, NULL, NULL, NULL) == ERROR_SUCCESS; v++)
2067 {
2068 int j;
2069
2070 for (j = 0; j < sizeof(values)/sizeof(struct compat_value); j++)
2071 if (lstrcmpA(values[j].nameA, valueA) == 0)
2072 {
2073 expected |= values[j].value;
2074 break;
2075 }
2076
2077 length = sizeof(valueA);
2078 }
2079
2080 pGUIDFromStringA(keyA, &clsid);
2081 got = pSHGetObjectCompatFlags(NULL, &clsid);
2082 ok(got == expected, "got 0x%08x, expected 0x%08x. Key %s\n", got, expected, keyA);
2083
2084 RegCloseKey(clsid_key);
2085 }
2086 }
2087
2088 RegCloseKey(root);
2089 }
2090
2091 typedef struct {
2092 IOleCommandTarget IOleCommandTarget_iface;
2093 LONG ref;
2094 } IOleCommandTargetImpl;
2095
2096 static inline IOleCommandTargetImpl *impl_from_IOleCommandTarget(IOleCommandTarget *iface)
2097 {
2098 return CONTAINING_RECORD(iface, IOleCommandTargetImpl, IOleCommandTarget_iface);
2099 }
2100
2101 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl;
2102
2103 static IOleCommandTarget* IOleCommandTargetImpl_Construct(void)
2104 {
2105 IOleCommandTargetImpl *obj;
2106
2107 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2108 obj->IOleCommandTarget_iface.lpVtbl = &IOleCommandTargetImpl_Vtbl;
2109 obj->ref = 1;
2110
2111 return &obj->IOleCommandTarget_iface;
2112 }
2113
2114 static HRESULT WINAPI IOleCommandTargetImpl_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppvObj)
2115 {
2116 IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface);
2117
2118 if (IsEqualIID(riid, &IID_IUnknown) ||
2119 IsEqualIID(riid, &IID_IOleCommandTarget))
2120 {
2121 *ppvObj = This;
2122 }
2123
2124 if(*ppvObj)
2125 {
2126 IOleCommandTarget_AddRef(iface);
2127 return S_OK;
2128 }
2129
2130 return E_NOINTERFACE;
2131 }
2132
2133 static ULONG WINAPI IOleCommandTargetImpl_AddRef(IOleCommandTarget *iface)
2134 {
2135 IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface);
2136 return InterlockedIncrement(&This->ref);
2137 }
2138
2139 static ULONG WINAPI IOleCommandTargetImpl_Release(IOleCommandTarget *iface)
2140 {
2141 IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface);
2142 ULONG ref = InterlockedDecrement(&This->ref);
2143
2144 if (!ref)
2145 {
2146 HeapFree(GetProcessHeap(), 0, This);
2147 return 0;
2148 }
2149 return ref;
2150 }
2151
2152 static HRESULT WINAPI IOleCommandTargetImpl_QueryStatus(
2153 IOleCommandTarget *iface, const GUID *group, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText)
2154 {
2155 return E_NOTIMPL;
2156 }
2157
2158 static HRESULT WINAPI IOleCommandTargetImpl_Exec(
2159 IOleCommandTarget *iface,
2160 const GUID *CmdGroup,
2161 DWORD nCmdID,
2162 DWORD nCmdexecopt,
2163 VARIANT *pvaIn,
2164 VARIANT *pvaOut)
2165 {
2166 add_call(&trace_got, 3, CmdGroup, (void*)(DWORD_PTR)nCmdID, (void*)(DWORD_PTR)nCmdexecopt, pvaIn, pvaOut);
2167 return S_OK;
2168 }
2169
2170 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl =
2171 {
2172 IOleCommandTargetImpl_QueryInterface,
2173 IOleCommandTargetImpl_AddRef,
2174 IOleCommandTargetImpl_Release,
2175 IOleCommandTargetImpl_QueryStatus,
2176 IOleCommandTargetImpl_Exec
2177 };
2178
2179 typedef struct {
2180 IServiceProvider IServiceProvider_iface;
2181 LONG ref;
2182 } IServiceProviderImpl;
2183
2184 static inline IServiceProviderImpl *impl_from_IServiceProvider(IServiceProvider *iface)
2185 {
2186 return CONTAINING_RECORD(iface, IServiceProviderImpl, IServiceProvider_iface);
2187 }
2188
2189 typedef struct {
2190 IProfferService IProfferService_iface;
2191 LONG ref;
2192 } IProfferServiceImpl;
2193
2194 static inline IProfferServiceImpl *impl_from_IProfferService(IProfferService *iface)
2195 {
2196 return CONTAINING_RECORD(iface, IProfferServiceImpl, IProfferService_iface);
2197 }
2198
2199
2200 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl;
2201 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl;
2202
2203 static IServiceProvider* IServiceProviderImpl_Construct(void)
2204 {
2205 IServiceProviderImpl *obj;
2206
2207 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2208 obj->IServiceProvider_iface.lpVtbl = &IServiceProviderImpl_Vtbl;
2209 obj->ref = 1;
2210
2211 return &obj->IServiceProvider_iface;
2212 }
2213
2214 static IProfferService* IProfferServiceImpl_Construct(void)
2215 {
2216 IProfferServiceImpl *obj;
2217
2218 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2219 obj->IProfferService_iface.lpVtbl = &IProfferServiceImpl_Vtbl;
2220 obj->ref = 1;
2221
2222 return &obj->IProfferService_iface;
2223 }
2224
2225 static HRESULT WINAPI IServiceProviderImpl_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppvObj)
2226 {
2227 IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
2228
2229 if (IsEqualIID(riid, &IID_IUnknown) ||
2230 IsEqualIID(riid, &IID_IServiceProvider))
2231 {
2232 *ppvObj = This;
2233 }
2234
2235 if(*ppvObj)
2236 {
2237 IServiceProvider_AddRef(iface);
2238 /* native uses redefined IID_IServiceProvider symbol, so we can't compare pointers */
2239 if (IsEqualIID(riid, &IID_IServiceProvider))
2240 add_call(&trace_got, 1, iface, &IID_IServiceProvider, 0, 0, 0);
2241 return S_OK;
2242 }
2243
2244 return E_NOINTERFACE;
2245 }
2246
2247 static ULONG WINAPI IServiceProviderImpl_AddRef(IServiceProvider *iface)
2248 {
2249 IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
2250 return InterlockedIncrement(&This->ref);
2251 }
2252
2253 static ULONG WINAPI IServiceProviderImpl_Release(IServiceProvider *iface)
2254 {
2255 IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
2256 ULONG ref = InterlockedDecrement(&This->ref);
2257
2258 if (!ref)
2259 {
2260 HeapFree(GetProcessHeap(), 0, This);
2261 return 0;
2262 }
2263 return ref;
2264 }
2265
2266 static HRESULT WINAPI IServiceProviderImpl_QueryService(
2267 IServiceProvider *iface, REFGUID service, REFIID riid, void **ppv)
2268 {
2269 /* native uses redefined pointer for IID_IOleCommandTarget, not one from uuid.lib */
2270 if (IsEqualIID(riid, &IID_IOleCommandTarget))
2271 {
2272 add_call(&trace_got, 2, iface, service, &IID_IOleCommandTarget, 0, 0);
2273 *ppv = IOleCommandTargetImpl_Construct();
2274 }
2275 if (IsEqualIID(riid, &IID_IProfferService))
2276 {
2277 if (IsEqualIID(service, &IID_IProfferService))
2278 add_call(&trace_got, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2279 *ppv = IProfferServiceImpl_Construct();
2280 }
2281 return S_OK;
2282 }
2283
2284 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl =
2285 {
2286 IServiceProviderImpl_QueryInterface,
2287 IServiceProviderImpl_AddRef,
2288 IServiceProviderImpl_Release,
2289 IServiceProviderImpl_QueryService
2290 };
2291
2292 static void test_IUnknown_QueryServiceExec(void)
2293 {
2294 IServiceProvider *provider;
2295 static const GUID dummy_serviceid = { 0xdeadbeef };
2296 static const GUID dummy_groupid = { 0xbeefbeef };
2297 call_trace_t trace_expected;
2298 HRESULT hr;
2299
2300 provider = IServiceProviderImpl_Construct();
2301
2302 /* null source pointer */
2303 hr = pIUnknown_QueryServiceExec(NULL, &dummy_serviceid, &dummy_groupid, 0, 0, 0, 0);
2304 ok(hr == E_FAIL ||
2305 hr == E_NOTIMPL, /* win 8 */
2306 "got 0x%08x\n", hr);
2307
2308 /* expected trace:
2309 IUnknown_QueryServiceExec( ptr1, serviceid, groupid, arg1, arg2, arg3, arg4);
2310 -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &prov );
2311 -> IServiceProvider_QueryService( prov, serviceid, &IID_IOleCommandTarget, &obj );
2312 -> IOleCommandTarget_Exec( obj, groupid, arg1, arg2, arg3, arg4 );
2313 */
2314 init_call_trace(&trace_expected);
2315
2316 add_call(&trace_expected, 1, provider, &IID_IServiceProvider, 0, 0, 0);
2317 add_call(&trace_expected, 2, provider, &dummy_serviceid, &IID_IOleCommandTarget, 0, 0);
2318 add_call(&trace_expected, 3, &dummy_groupid, (void*)0x1, (void*)0x2, (void*)0x3, (void*)0x4);
2319
2320 init_call_trace(&trace_got);
2321 hr = pIUnknown_QueryServiceExec((IUnknown*)provider, &dummy_serviceid, &dummy_groupid, 0x1, 0x2, (void*)0x3, (void*)0x4);
2322 ok(hr == S_OK, "got 0x%08x\n", hr);
2323
2324 ok_trace(&trace_expected, &trace_got);
2325
2326 free_call_trace(&trace_expected);
2327 free_call_trace(&trace_got);
2328
2329 IServiceProvider_Release(provider);
2330 }
2331
2332
2333 static HRESULT WINAPI IProfferServiceImpl_QueryInterface(IProfferService *iface, REFIID riid, void **ppvObj)
2334 {
2335 IProfferServiceImpl *This = impl_from_IProfferService(iface);
2336
2337 if (IsEqualIID(riid, &IID_IUnknown) ||
2338 IsEqualIID(riid, &IID_IProfferService))
2339 {
2340 *ppvObj = This;
2341 }
2342 else if (IsEqualIID(riid, &IID_IServiceProvider))
2343 {
2344 *ppvObj = IServiceProviderImpl_Construct();
2345 add_call(&trace_got, 1, iface, &IID_IServiceProvider, 0, 0, 0);
2346 return S_OK;
2347 }
2348
2349 if(*ppvObj)
2350 {
2351 IProfferService_AddRef(iface);
2352 return S_OK;
2353 }
2354
2355 return E_NOINTERFACE;
2356 }
2357
2358 static ULONG WINAPI IProfferServiceImpl_AddRef(IProfferService *iface)
2359 {
2360 IProfferServiceImpl *This = impl_from_IProfferService(iface);
2361 return InterlockedIncrement(&This->ref);
2362 }
2363
2364 static ULONG WINAPI IProfferServiceImpl_Release(IProfferService *iface)
2365 {
2366 IProfferServiceImpl *This = impl_from_IProfferService(iface);
2367 ULONG ref = InterlockedDecrement(&This->ref);
2368
2369 if (!ref)
2370 {
2371 HeapFree(GetProcessHeap(), 0, This);
2372 return 0;
2373 }
2374 return ref;
2375 }
2376
2377 static HRESULT WINAPI IProfferServiceImpl_ProfferService(IProfferService *iface,
2378 REFGUID service, IServiceProvider *pService, DWORD *pCookie)
2379 {
2380 *pCookie = 0xdeadbeef;
2381 add_call(&trace_got, 3, service, pService, pCookie, 0, 0);
2382 return S_OK;
2383 }
2384
2385 static HRESULT WINAPI IProfferServiceImpl_RevokeService(IProfferService *iface, DWORD cookie)
2386 {
2387 add_call(&trace_got, 4, (void*)(DWORD_PTR)cookie, 0, 0, 0, 0);
2388 return S_OK;
2389 }
2390
2391 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl =
2392 {
2393 IProfferServiceImpl_QueryInterface,
2394 IProfferServiceImpl_AddRef,
2395 IProfferServiceImpl_Release,
2396 IProfferServiceImpl_ProfferService,
2397 IProfferServiceImpl_RevokeService
2398 };
2399
2400 static void test_IUnknown_ProfferService(void)
2401 {
2402 IServiceProvider *provider;
2403 IProfferService *proff;
2404 static const GUID dummy_serviceid = { 0xdeadbeef };
2405 call_trace_t trace_expected;
2406 HRESULT hr;
2407 DWORD cookie;
2408
2409 provider = IServiceProviderImpl_Construct();
2410 proff = IProfferServiceImpl_Construct();
2411
2412 /* null source pointer */
2413 hr = pIUnknown_ProfferService(NULL, &dummy_serviceid, 0, 0);
2414 ok(hr == E_FAIL ||
2415 hr == E_NOTIMPL, /* win 8 */
2416 "got 0x%08x\n", hr);
2417
2418 /* expected trace:
2419 IUnknown_ProfferService( ptr1, serviceid, arg1, arg2);
2420 -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &provider );
2421 -> IServiceProvider_QueryService( provider, &IID_IProfferService, &IID_IProfferService, &proffer );
2422
2423 if (service pointer not null):
2424 -> IProfferService_ProfferService( proffer, serviceid, arg1, arg2 );
2425 else
2426 -> IProfferService_RevokeService( proffer, *arg2 );
2427 */
2428 init_call_trace(&trace_expected);
2429
2430 add_call(&trace_expected, 1, proff, &IID_IServiceProvider, 0, 0, 0);
2431 add_call(&trace_expected, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2432 add_call(&trace_expected, 3, &dummy_serviceid, provider, &cookie, 0, 0);
2433
2434 init_call_trace(&trace_got);
2435 cookie = 0;
2436 hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, provider, &cookie);
2437 ok(hr == S_OK, "got 0x%08x\n", hr);
2438 ok(cookie == 0xdeadbeef, "got %x\n", cookie);
2439
2440 ok_trace(&trace_expected, &trace_got);
2441 free_call_trace(&trace_got);
2442 free_call_trace(&trace_expected);
2443
2444 /* same with ::Revoke path */
2445 init_call_trace(&trace_expected);
2446
2447 add_call(&trace_expected, 1, proff, &IID_IServiceProvider, 0, 0, 0);
2448 add_call(&trace_expected, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2449 add_call(&trace_expected, 4, (void*)(DWORD_PTR)cookie, 0, 0, 0, 0);
2450
2451 init_call_trace(&trace_got);
2452 ok(cookie != 0, "got %x\n", cookie);
2453 hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, 0, &cookie);
2454 ok(hr == S_OK, "got 0x%08x\n", hr);
2455 ok(cookie == 0, "got %x\n", cookie);
2456 ok_trace(&trace_expected, &trace_got);
2457 free_call_trace(&trace_got);
2458 free_call_trace(&trace_expected);
2459
2460 IServiceProvider_Release(provider);
2461 IProfferService_Release(proff);
2462 }
2463
2464 static void test_SHCreateWorkerWindowA(void)
2465 {
2466 WNDCLASSA cliA;
2467 char classA[20];
2468 HWND hwnd;
2469 LONG_PTR ret;
2470 BOOL res;
2471
2472 hwnd = pSHCreateWorkerWindowA(0, NULL, 0, 0, 0, 0);
2473 ok(hwnd != 0, "expected window\n");
2474
2475 GetClassNameA(hwnd, classA, 20);
2476 ok(lstrcmpA(classA, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA);
2477
2478 ret = GetWindowLongPtrA(hwnd, 0);
2479 ok(ret == 0, "got %ld\n", ret);
2480
2481 /* class info */
2482 memset(&cliA, 0, sizeof(cliA));
2483 res = GetClassInfoA(GetModuleHandleA("shlwapi.dll"), "WorkerA", &cliA);
2484 ok(res, "failed to get class info\n");
2485 ok(cliA.style == 0, "got 0x%08x\n", cliA.style);
2486 ok(cliA.cbClsExtra == 0, "got %d\n", cliA.cbClsExtra);
2487 ok(cliA.cbWndExtra == sizeof(LONG_PTR), "got %d\n", cliA.cbWndExtra);
2488 ok(cliA.lpszMenuName == 0, "got %s\n", cliA.lpszMenuName);
2489
2490 DestroyWindow(hwnd);
2491
2492 /* set extra bytes */
2493 hwnd = pSHCreateWorkerWindowA(0, NULL, 0, 0, 0, 0xdeadbeef);
2494 ok(hwnd != 0, "expected window\n");
2495
2496 GetClassNameA(hwnd, classA, 20);
2497 ok(lstrcmpA(classA, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA);
2498
2499 ret = GetWindowLongPtrA(hwnd, 0);
2500 ok(ret == 0xdeadbeef, "got %ld\n", ret);
2501
2502 /* test exstyle */
2503 ret = GetWindowLongA(hwnd, GWL_EXSTYLE);
2504 ok(ret == WS_EX_WINDOWEDGE ||
2505 ret == (WS_EX_WINDOWEDGE|WS_EX_LAYOUTRTL) /* systems with RTL locale */, "0x%08lx\n", ret);
2506
2507 DestroyWindow(hwnd);
2508
2509 hwnd = pSHCreateWorkerWindowA(0, NULL, WS_EX_TOOLWINDOW, 0, 0, 0);
2510 ret = GetWindowLongA(hwnd, GWL_EXSTYLE);
2511 ok(ret == (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW) ||
2512 ret == (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW|WS_EX_LAYOUTRTL) /* systems with RTL locale */, "0x%08lx\n", ret);
2513 DestroyWindow(hwnd);
2514 }
2515
2516 static HRESULT WINAPI SF_QueryInterface(IShellFolder *iface,
2517 REFIID riid, void **ppv)
2518 {
2519 /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */
2520 ok(!IsEqualGUID(&IID_IShellFolder, riid),
2521 "Unexpected QI for IShellFolder\n");
2522 return E_NOINTERFACE;
2523 }
2524
2525 static ULONG WINAPI SF_AddRef(IShellFolder *iface)
2526 {
2527 return 2;
2528 }
2529
2530 static ULONG WINAPI SF_Release(IShellFolder *iface)
2531 {
2532 return 1;
2533 }
2534
2535 static HRESULT WINAPI SF_ParseDisplayName(IShellFolder *iface,
2536 HWND owner, LPBC reserved, LPOLESTR displayName, ULONG *eaten,
2537 LPITEMIDLIST *idl, ULONG *attr)
2538 {
2539 ok(0, "Didn't expect ParseDisplayName\n");
2540 return E_NOTIMPL;
2541 }
2542
2543 static HRESULT WINAPI SF_EnumObjects(IShellFolder *iface,
2544 HWND owner, SHCONTF flags, IEnumIDList **enm)
2545 {
2546 *enm = (IEnumIDList*)0xcafebabe;
2547 return S_OK;
2548 }
2549
2550 static HRESULT WINAPI SF_BindToObject(IShellFolder *iface,
2551 LPCITEMIDLIST idl, LPBC reserved, REFIID riid, void **obj)
2552 {
2553 ok(0, "Didn't expect BindToObject\n");
2554 return E_NOTIMPL;
2555 }
2556
2557 static HRESULT WINAPI SF_BindToStorage(IShellFolder *iface,
2558 LPCITEMIDLIST idl, LPBC reserved, REFIID riid, void **obj)
2559 {
2560 ok(0, "Didn't expect BindToStorage\n");
2561 return E_NOTIMPL;
2562 }
2563
2564 static HRESULT WINAPI SF_CompareIDs(IShellFolder *iface,
2565 LPARAM lparam, LPCITEMIDLIST idl1, LPCITEMIDLIST idl2)
2566 {
2567 ok(0, "Didn't expect CompareIDs\n");
2568 return E_NOTIMPL;
2569 }
2570
2571 static HRESULT WINAPI SF_CreateViewObject(IShellFolder *iface,
2572 HWND owner, REFIID riid, void **out)
2573 {
2574 ok(0, "Didn't expect CreateViewObject\n");
2575 return E_NOTIMPL;
2576 }
2577
2578 static HRESULT WINAPI SF_GetAttributesOf(IShellFolder *iface,
2579 #ifdef __REACTOS__
2580 UINT cidl, PCUITEMID_CHILD_ARRAY idl, SFGAOF *inOut)
2581 #else
2582 UINT cidl, LPCITEMIDLIST *idl, SFGAOF *inOut)
2583 #endif
2584 {
2585 ok(0, "Didn't expect GetAttributesOf\n");
2586 return E_NOTIMPL;
2587 }
2588
2589 static HRESULT WINAPI SF_GetUIObjectOf(IShellFolder *iface,
2590 #ifdef __REACTOS__
2591 HWND owner, UINT cidl, PCUITEMID_CHILD_ARRAY idls, REFIID riid, UINT *inOut,
2592 #else
2593 HWND owner, UINT cidl, LPCITEMIDLIST *idls, REFIID riid, UINT *inOut,
2594 #endif
2595 void **out)
2596 {
2597 ok(0, "Didn't expect GetUIObjectOf\n");
2598 return E_NOTIMPL;
2599 }
2600
2601 static HRESULT WINAPI SF_GetDisplayNameOf(IShellFolder *iface,
2602 LPCITEMIDLIST idl, SHGDNF flags, STRRET *name)
2603 {
2604 ok(0, "Didn't expect GetDisplayNameOf\n");
2605 return E_NOTIMPL;
2606 }
2607
2608 static HRESULT WINAPI SF_SetNameOf(IShellFolder *iface,
2609 HWND hwnd, LPCITEMIDLIST idl, LPCOLESTR name, SHGDNF flags,
2610 LPITEMIDLIST *idlOut)
2611 {
2612 ok(0, "Didn't expect SetNameOf\n");
2613 return E_NOTIMPL;
2614 }
2615
2616 static IShellFolderVtbl ShellFolderVtbl = {
2617 SF_QueryInterface,
2618 SF_AddRef,
2619 SF_Release,
2620 SF_ParseDisplayName,
2621 SF_EnumObjects,
2622 SF_BindToObject,
2623 SF_BindToStorage,
2624 SF_CompareIDs,
2625 SF_CreateViewObject,
2626 SF_GetAttributesOf,
2627 SF_GetUIObjectOf,
2628 SF_GetDisplayNameOf,
2629 SF_SetNameOf
2630 };
2631
2632 static IShellFolder ShellFolder = { &ShellFolderVtbl };
2633
2634 static void test_SHIShellFolder_EnumObjects(void)
2635 {
2636 IEnumIDList *enm;
2637 HRESULT hres;
2638 IShellFolder *folder;
2639
2640 if(!pSHIShellFolder_EnumObjects){ /* win7 and later */
2641 win_skip("SHIShellFolder_EnumObjects not available\n");
2642 return;
2643 }
2644
2645 if(0){
2646 /* NULL object crashes on Windows */
2647 pSHIShellFolder_EnumObjects(NULL, NULL, 0, NULL);
2648 }
2649
2650 /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */
2651 enm = (IEnumIDList*)0xdeadbeef;
2652 hres = pSHIShellFolder_EnumObjects(&ShellFolder, NULL, 0, &enm);
2653 ok(hres == S_OK, "SHIShellFolder_EnumObjects failed: 0x%08x\n", hres);
2654 ok(enm == (IEnumIDList*)0xcafebabe, "Didn't get expected enumerator location, instead: %p\n", enm);
2655
2656 /* SHIShellFolder_EnumObjects isn't strict about the IShellFolder object */
2657 hres = SHGetDesktopFolder(&folder);
2658 ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
2659
2660 enm = NULL;
2661 hres = pSHIShellFolder_EnumObjects(folder, NULL, 0, &enm);
2662 ok(hres == S_OK, "SHIShellFolder_EnumObjects failed: 0x%08x\n", hres);
2663 ok(enm != NULL, "Didn't get an enumerator\n");
2664 if(enm)
2665 IEnumIDList_Release(enm);
2666
2667 IShellFolder_Release(folder);
2668 }
2669
2670 static BOOL write_inifile(LPCWSTR filename)
2671 {
2672 DWORD written;
2673 HANDLE file;
2674
2675 static const char data[] =
2676 "[TestApp]\r\n"
2677 "AKey=1\r\n"
2678 "AnotherKey=asdf\r\n";
2679
2680 file = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
2681 if(file == INVALID_HANDLE_VALUE) {
2682 win_skip("failed to create ini file at %s\n", wine_dbgstr_w(filename));
2683 return FALSE;
2684 }
2685
2686 WriteFile(file, data, sizeof(data), &written, NULL);
2687
2688 CloseHandle(file);
2689
2690 return TRUE;
2691 }
2692
2693 #define verify_inifile(f, e) r_verify_inifile(__LINE__, f, e)
2694 static void r_verify_inifile(unsigned l, LPCWSTR filename, LPCSTR exp)
2695 {
2696 HANDLE file;
2697 CHAR buf[1024];
2698 DWORD read;
2699
2700 file = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
2701
2702 if(file == INVALID_HANDLE_VALUE)
2703 return;
2704
2705 ReadFile(file, buf, sizeof(buf) * sizeof(CHAR), &read, NULL);
2706 buf[read] = '\0';
2707
2708 CloseHandle(file);
2709
2710 ok_(__FILE__,l)(!strcmp(buf, exp), "Expected:\n%s\nGot:\n%s\n", exp,
2711 buf);
2712 }
2713
2714 static void test_SHGetIniString(void)
2715 {
2716 DWORD ret;
2717 WCHAR out[64] = {0};
2718
2719 static const WCHAR TestAppW[] = {'T','e','s','t','A','p','p',0};
2720 static const WCHAR AKeyW[] = {'A','K','e','y',0};
2721 static const WCHAR AnotherKeyW[] = {'A','n','o','t','h','e','r','K','e','y',0};
2722 static const WCHAR JunkKeyW[] = {'J','u','n','k','K','e','y',0};
2723 static const WCHAR testpathW[] = {'C',':','\\','t','e','s','t','.','i'