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