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