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