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