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