mshtml: Don't use PRInt32 in property getters implementations.
[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 succeed
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         IDispatch_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         IEnumConnections_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         IConnectionPoint_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         IEnumConnectionPoints_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         IConnectionPoint_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         IConnectionPointContainer_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                 IConnectionPoint_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         IPropertyBag_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     rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, szName1, &out);
1542     ok(rc == DISP_E_BADVARTYPE || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
1543     ok(out == 0xfeedface  || broken(out == 0xfeedfa00), "value should not have changed %x\n",out);
1544     IUnknown_Release((IUnknown*)pb);
1545 }
1546
1547
1548
1549 static void test_SHSetWindowBits(void)
1550 {
1551     HWND hwnd;
1552     DWORD style, styleold;
1553     WNDCLASSA clsA;
1554
1555     if(!pSHSetWindowBits)
1556     {
1557         win_skip("SHSetWindowBits is not available\n");
1558         return;
1559     }
1560
1561     clsA.style = 0;
1562     clsA.lpfnWndProc = DefWindowProcA;
1563     clsA.cbClsExtra = 0;
1564     clsA.cbWndExtra = 0;
1565     clsA.hInstance = GetModuleHandleA(NULL);
1566     clsA.hIcon = 0;
1567     clsA.hCursor = LoadCursorA(0, IDC_ARROW);
1568     clsA.hbrBackground = NULL;
1569     clsA.lpszMenuName = NULL;
1570     clsA.lpszClassName = "Shlwapi test class";
1571     RegisterClassA(&clsA);
1572
1573     hwnd = CreateWindowA("Shlwapi test class", "Test", WS_VISIBLE, 0, 0, 100, 100,
1574                           NULL, NULL, GetModuleHandle(NULL), 0);
1575     ok(IsWindow(hwnd), "failed to create window\n");
1576
1577     /* null window */
1578     SetLastError(0xdeadbeef);
1579     style = pSHSetWindowBits(NULL, GWL_STYLE, 0, 0);
1580     ok(style == 0, "expected 0 retval, got %d\n", style);
1581     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
1582         broken(GetLastError() == 0xdeadbeef), /* Win9x/WinMe */
1583         "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
1584
1585     /* zero mask, zero flags */
1586     styleold = GetWindowLongA(hwnd, GWL_STYLE);
1587     style = pSHSetWindowBits(hwnd, GWL_STYLE, 0, 0);
1588     ok(styleold == style, "expected old style\n");
1589     ok(styleold == GetWindowLongA(hwnd, GWL_STYLE), "expected to keep old style\n");
1590
1591     /* test mask */
1592     styleold = GetWindowLongA(hwnd, GWL_STYLE);
1593     ok(styleold & WS_VISIBLE, "expected WS_VISIBLE\n");
1594     style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1595
1596     ok(style == styleold, "expected previous style, got %x\n", style);
1597     ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1598
1599     /* test mask, unset style bit used */
1600     styleold = GetWindowLongA(hwnd, GWL_STYLE);
1601     style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1602     ok(style == styleold, "expected previous style, got %x\n", style);
1603     ok(styleold == GetWindowLongA(hwnd, GWL_STYLE), "expected to keep old style\n");
1604
1605     /* set back with flags */
1606     styleold = GetWindowLongA(hwnd, GWL_STYLE);
1607     style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, WS_VISIBLE);
1608     ok(style == styleold, "expected previous style, got %x\n", style);
1609     ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "expected updated style\n");
1610
1611     /* reset and try to set without a mask */
1612     pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1613     ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1614     styleold = GetWindowLongA(hwnd, GWL_STYLE);
1615     style = pSHSetWindowBits(hwnd, GWL_STYLE, 0, WS_VISIBLE);
1616     ok(style == styleold, "expected previous style, got %x\n", style);
1617     ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1618
1619     DestroyWindow(hwnd);
1620
1621     UnregisterClassA("Shlwapi test class", GetModuleHandleA(NULL));
1622 }
1623
1624 static void test_SHFormatDateTimeA(void)
1625 {
1626     FILETIME UNALIGNED filetime;
1627     CHAR buff[100], buff2[100], buff3[100];
1628     SYSTEMTIME st;
1629     DWORD flags;
1630     INT ret;
1631
1632     if(!pSHFormatDateTimeA)
1633     {
1634         win_skip("pSHFormatDateTimeA isn't available\n");
1635         return;
1636     }
1637
1638 if (0)
1639 {
1640     /* crashes on native */
1641     pSHFormatDateTimeA(NULL, NULL, NULL, 0);
1642 }
1643
1644     GetLocalTime(&st);
1645     SystemTimeToFileTime(&st, &filetime);
1646     /* SHFormatDateTime expects input as utc */
1647     LocalFileTimeToFileTime(&filetime, &filetime);
1648
1649     /* no way to get required buffer length here */
1650     SetLastError(0xdeadbeef);
1651     ret = pSHFormatDateTimeA(&filetime, NULL, NULL, 0);
1652     ok(ret == 0, "got %d\n", ret);
1653     ok(GetLastError() == 0xdeadbeef || broken(GetLastError() == ERROR_SUCCESS /* Win7 */),
1654         "expected 0xdeadbeef, got %d\n", GetLastError());
1655
1656     SetLastError(0xdeadbeef);
1657     buff[0] = 'a'; buff[1] = 0;
1658     ret = pSHFormatDateTimeA(&filetime, NULL, buff, 0);
1659     ok(ret == 0, "got %d\n", ret);
1660     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1661     ok(buff[0] == 'a', "expected same string, got %s\n", buff);
1662
1663     /* flags needs to have FDTF_NOAUTOREADINGORDER for these tests to succeed on Vista+ */
1664
1665     /* all combinations documented as invalid succeeded */
1666     flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTTIME | FDTF_LONGTIME;
1667     SetLastError(0xdeadbeef);
1668     ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1669     ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1670     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1671
1672     flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_LONGDATE;
1673     SetLastError(0xdeadbeef);
1674     ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1675     ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1676     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1677
1678     flags =  FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE;
1679     SetLastError(0xdeadbeef);
1680     ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1681     ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1682     ok(GetLastError() == 0xdeadbeef ||
1683         broken(GetLastError() == ERROR_INVALID_FLAGS), /* Win9x/WinMe */
1684         "expected 0xdeadbeef, got %d\n", GetLastError());
1685
1686     /* now check returned strings */
1687     flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTTIME;
1688     ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1689     ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1690     ret = GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff2, sizeof(buff2));
1691     ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1692     ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1693
1694     flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGTIME;
1695     ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1696     ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1697     ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2));
1698     ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1699     ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1700
1701     /* both time flags */
1702     flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGTIME | FDTF_SHORTTIME;
1703     ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1704     ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1705     ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2));
1706     ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1707     ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1708
1709     flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE;
1710     ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1711     ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1712     ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1713     ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1714     ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1715
1716     flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE;
1717     ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1718     ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1719     ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1720     ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1721     ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1722
1723     /* both date flags */
1724     flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_SHORTDATE;
1725     ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1726     ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1727     ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1728     ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1729     ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1730
1731     /* various combinations of date/time flags */
1732     flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_SHORTTIME;
1733     ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1734     ok(ret == lstrlenA(buff)+1, "got %d, length %d\n", ret, lstrlenA(buff)+1);
1735     ret = GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3));
1736     ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1737     ok(lstrcmpA(buff3, buff + lstrlenA(buff) - lstrlenA(buff3)) == 0,
1738        "expected (%s), got (%s) for time part\n",
1739        buff3, buff + lstrlenA(buff) - lstrlenA(buff3));
1740     ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1741     ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1742     buff[lstrlenA(buff2)] = '\0';
1743     ok(lstrcmpA(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1744        buff2, buff);
1745
1746     flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_LONGTIME;
1747     ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1748     ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1749     ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3));
1750     ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1751     ok(lstrcmpA(buff3, buff + lstrlenA(buff) - lstrlenA(buff3)) == 0,
1752        "expected (%s), got (%s) for time part\n",
1753        buff3, buff + lstrlenA(buff) - lstrlenA(buff3));
1754     ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1755     ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1756     buff[lstrlenA(buff2)] = '\0';
1757     ok(lstrcmpA(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1758        buff2, buff);
1759
1760     flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_SHORTTIME;
1761     ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1762     ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1763     ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1764     ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1765     strcat(buff2, " ");
1766     ret = GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3));
1767     ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1768     strcat(buff2, buff3);
1769     ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1770
1771     flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_LONGTIME;
1772     ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1773     ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1774     ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1775     ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1776     strcat(buff2, " ");
1777     ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3));
1778     ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1779     strcat(buff2, buff3);
1780     ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1781 }
1782
1783 static void test_SHFormatDateTimeW(void)
1784 {
1785     FILETIME UNALIGNED filetime;
1786     WCHAR buff[100], buff2[100], buff3[100], *p1, *p2;
1787     SYSTEMTIME st;
1788     DWORD flags;
1789     INT ret;
1790     static const WCHAR spaceW[] = {' ',0};
1791 #define UNICODE_LTR_MARK 0x200e
1792
1793     if(!pSHFormatDateTimeW)
1794     {
1795         win_skip("pSHFormatDateTimeW isn't available\n");
1796         return;
1797     }
1798
1799 if (0)
1800 {
1801     /* crashes on native */
1802     pSHFormatDateTimeW(NULL, NULL, NULL, 0);
1803 }
1804
1805     GetLocalTime(&st);
1806     SystemTimeToFileTime(&st, &filetime);
1807     /* SHFormatDateTime expects input as utc */
1808     LocalFileTimeToFileTime(&filetime, &filetime);
1809
1810     /* no way to get required buffer length here */
1811     SetLastError(0xdeadbeef);
1812     ret = pSHFormatDateTimeW(&filetime, NULL, NULL, 0);
1813     ok(ret == 0, "expected 0, got %d\n", ret);
1814     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1815
1816     SetLastError(0xdeadbeef);
1817     buff[0] = 'a'; buff[1] = 0;
1818     ret = pSHFormatDateTimeW(&filetime, NULL, buff, 0);
1819     ok(ret == 0, "expected 0, got %d\n", ret);
1820     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1821     ok(buff[0] == 'a', "expected same string\n");
1822
1823     /* all combinations documented as invalid succeeded */
1824     flags = FDTF_SHORTTIME | FDTF_LONGTIME;
1825     SetLastError(0xdeadbeef);
1826     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1827     ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1828        "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1829     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1830
1831     flags = FDTF_SHORTDATE | FDTF_LONGDATE;
1832     SetLastError(0xdeadbeef);
1833     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1834     ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1835        "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1836     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1837
1838     flags = FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE;
1839     SetLastError(0xdeadbeef);
1840     buff[0] = 0; /* NT4 doesn't clear the buffer on failure */
1841     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1842     ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1843        "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1844     ok(GetLastError() == 0xdeadbeef ||
1845         broken(GetLastError() == ERROR_INVALID_FLAGS), /* Win9x/WinMe/NT4 */
1846         "expected 0xdeadbeef, got %d\n", GetLastError());
1847
1848     /* now check returned strings */
1849     flags = FDTF_SHORTTIME;
1850     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1851     ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1852        "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1853     SetLastError(0xdeadbeef);
1854     ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1855     if (ret == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1856     {
1857         win_skip("Needed W-functions are not implemented\n");
1858         return;
1859     }
1860     ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1861     ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1862
1863     flags = FDTF_LONGTIME;
1864     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1865     ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1866        "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1867     ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1868     ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1869     ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1870
1871     /* both time flags */
1872     flags = FDTF_LONGTIME | FDTF_SHORTTIME;
1873     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1874     ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1875        "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1876     ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1877     ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1878     ok(lstrcmpW(buff, buff2) == 0, "expected equal string\n");
1879
1880     flags = FDTF_SHORTDATE;
1881     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1882     ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1883        "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1884     ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1885     ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1886     ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1887
1888     flags = FDTF_LONGDATE;
1889     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1890     ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1891        "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1892     ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1893     ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1894     ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1895
1896     /* both date flags */
1897     flags = FDTF_LONGDATE | FDTF_SHORTDATE;
1898     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1899     ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1900        "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1901     ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1902     ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1903     ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1904
1905     /* various combinations of date/time flags */
1906     flags = FDTF_LONGDATE | FDTF_SHORTTIME;
1907     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1908     ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1909        "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1910     ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1911     ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1912     ok(lstrcmpW(buff3, buff + lstrlenW(buff) - lstrlenW(buff3)) == 0,
1913        "expected (%s), got (%s) for time part\n",
1914        wine_dbgstr_w(buff3), wine_dbgstr_w(buff + lstrlenW(buff) - lstrlenW(buff3)));
1915     ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1916     ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1917     p1 = buff;
1918     p2 = buff2;
1919     while (*p2 != '\0')
1920     {
1921         while (*p1 == UNICODE_LTR_MARK)
1922             p1++;
1923         while (*p2 == UNICODE_LTR_MARK)
1924             p2++;
1925         p1++;
1926         p2++;
1927     }
1928     *p1 = '\0';
1929     ok(lstrcmpW(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1930        wine_dbgstr_w(buff2), wine_dbgstr_w(buff));
1931
1932     flags = FDTF_LONGDATE | FDTF_LONGTIME;
1933     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1934     ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1935        "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1936     ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1937     ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1938     ok(lstrcmpW(buff3, buff + lstrlenW(buff) - lstrlenW(buff3)) == 0,
1939        "expected (%s), got (%s) for time part\n",
1940        wine_dbgstr_w(buff3), wine_dbgstr_w(buff + lstrlenW(buff) - lstrlenW(buff3)));
1941     ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1942     ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1943     p1 = buff;
1944     p2 = buff2;
1945     while (*p2 != '\0')
1946     {
1947         while (*p1 == UNICODE_LTR_MARK)
1948             p1++;
1949         while (*p2 == UNICODE_LTR_MARK)
1950             p2++;
1951         p1++;
1952         p2++;
1953     }
1954     *p1 = '\0';
1955     ok(lstrcmpW(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1956        wine_dbgstr_w(buff2), wine_dbgstr_w(buff));
1957
1958     flags = FDTF_SHORTDATE | FDTF_SHORTTIME;
1959     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1960     ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1961        "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1962     ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1963     ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1964     lstrcatW(buff2, spaceW);
1965     ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1966     ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1967     lstrcatW(buff2, buff3);
1968     ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1969
1970     flags = FDTF_SHORTDATE | FDTF_LONGTIME;
1971     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1972     ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1973        "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1974     ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1975     ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1976     lstrcatW(buff2, spaceW);
1977     ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1978     ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1979     lstrcatW(buff2, buff3);
1980     ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1981 }
1982
1983 static void test_SHGetObjectCompatFlags(void)
1984 {
1985     struct compat_value {
1986         CHAR nameA[30];
1987         DWORD value;
1988     };
1989
1990     struct compat_value values[] = {
1991         { "OTNEEDSSFCACHE", 0x1 },
1992         { "NO_WEBVIEW", 0x2 },
1993         { "UNBINDABLE", 0x4 },
1994         { "PINDLL", 0x8 },
1995         { "NEEDSFILESYSANCESTOR", 0x10 },
1996         { "NOTAFILESYSTEM", 0x20 },
1997         { "CTXMENU_NOVERBS", 0x40 },
1998         { "CTXMENU_LIMITEDQI", 0x80 },
1999         { "COCREATESHELLFOLDERONLY", 0x100 },
2000         { "NEEDSSTORAGEANCESTOR", 0x200 },
2001         { "NOLEGACYWEBVIEW", 0x400 },
2002         { "CTXMENU_XPQCMFLAGS", 0x1000 },
2003         { "NOIPROPERTYSTORE", 0x2000 }
2004     };
2005
2006     static const char compat_path[] = "Software\\Microsoft\\Windows\\CurrentVersion\\ShellCompatibility\\Objects";
2007     void *pColorAdjustLuma = GetProcAddress(hShlwapi, "ColorAdjustLuma");
2008     CHAR keyA[39]; /* {CLSID} */
2009     HKEY root;
2010     DWORD ret;
2011     int i;
2012
2013     if (!pSHGetObjectCompatFlags)
2014     {
2015         win_skip("SHGetObjectCompatFlags isn't available\n");
2016         return;
2017     }
2018
2019     if (pColorAdjustLuma && pColorAdjustLuma == pSHGetObjectCompatFlags) /* win2k */
2020     {
2021         win_skip("Skipping SHGetObjectCompatFlags, same ordinal used for ColorAdjustLuma\n");
2022         return;
2023     }
2024
2025     /* null args */
2026     ret = pSHGetObjectCompatFlags(NULL, NULL);
2027     ok(ret == 0, "got %d\n", ret);
2028
2029     ret = RegOpenKeyA(HKEY_LOCAL_MACHINE, compat_path, &root);
2030     if (ret != ERROR_SUCCESS)
2031     {
2032         skip("No compatibility class data found\n");
2033         return;
2034     }
2035
2036     for (i = 0; RegEnumKeyA(root, i, keyA, sizeof(keyA)) == ERROR_SUCCESS; i++)
2037     {
2038         HKEY clsid_key;
2039
2040         if (RegOpenKeyA(root, keyA, &clsid_key) == ERROR_SUCCESS)
2041         {
2042             CHAR valueA[30];
2043             DWORD expected = 0, got, length = sizeof(valueA);
2044             CLSID clsid;
2045             int v;
2046
2047             for (v = 0; RegEnumValueA(clsid_key, v, valueA, &length, NULL, NULL, NULL, NULL) == ERROR_SUCCESS; v++)
2048             {
2049                 int j;
2050
2051                 for (j = 0; j < sizeof(values)/sizeof(struct compat_value); j++)
2052                     if (lstrcmpA(values[j].nameA, valueA) == 0)
2053                     {
2054                         expected |= values[j].value;
2055                         break;
2056                     }
2057
2058                 length = sizeof(valueA);
2059             }
2060
2061             pGUIDFromStringA(keyA, &clsid);
2062             got = pSHGetObjectCompatFlags(NULL, &clsid);
2063             ok(got == expected, "got 0x%08x, expected 0x%08x. Key %s\n", got, expected, keyA);
2064
2065             RegCloseKey(clsid_key);
2066         }
2067     }
2068
2069     RegCloseKey(root);
2070 }
2071
2072 typedef struct {
2073     IOleCommandTarget IOleCommandTarget_iface;
2074     LONG ref;
2075 } IOleCommandTargetImpl;
2076
2077 static inline IOleCommandTargetImpl *impl_from_IOleCommandTarget(IOleCommandTarget *iface)
2078 {
2079     return CONTAINING_RECORD(iface, IOleCommandTargetImpl, IOleCommandTarget_iface);
2080 }
2081
2082 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl;
2083
2084 static IOleCommandTarget* IOleCommandTargetImpl_Construct(void)
2085 {
2086     IOleCommandTargetImpl *obj;
2087
2088     obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2089     obj->IOleCommandTarget_iface.lpVtbl = &IOleCommandTargetImpl_Vtbl;
2090     obj->ref = 1;
2091
2092     return &obj->IOleCommandTarget_iface;
2093 }
2094
2095 static HRESULT WINAPI IOleCommandTargetImpl_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppvObj)
2096 {
2097     IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface);
2098
2099     if (IsEqualIID(riid, &IID_IUnknown) ||
2100         IsEqualIID(riid, &IID_IOleCommandTarget))
2101     {
2102         *ppvObj = This;
2103     }
2104
2105     if(*ppvObj)
2106     {
2107         IOleCommandTarget_AddRef(iface);
2108         return S_OK;
2109     }
2110
2111     return E_NOINTERFACE;
2112 }
2113
2114 static ULONG WINAPI IOleCommandTargetImpl_AddRef(IOleCommandTarget *iface)
2115 {
2116     IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface);
2117     return InterlockedIncrement(&This->ref);
2118 }
2119
2120 static ULONG WINAPI IOleCommandTargetImpl_Release(IOleCommandTarget *iface)
2121 {
2122     IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface);
2123     ULONG ref = InterlockedDecrement(&This->ref);
2124
2125     if (!ref)
2126     {
2127         HeapFree(GetProcessHeap(), 0, This);
2128         return 0;
2129     }
2130     return ref;
2131 }
2132
2133 static HRESULT WINAPI IOleCommandTargetImpl_QueryStatus(
2134     IOleCommandTarget *iface, const GUID *group, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText)
2135 {
2136     return E_NOTIMPL;
2137 }
2138
2139 static HRESULT WINAPI IOleCommandTargetImpl_Exec(
2140     IOleCommandTarget *iface,
2141     const GUID *CmdGroup,
2142     DWORD nCmdID,
2143     DWORD nCmdexecopt,
2144     VARIANT *pvaIn,
2145     VARIANT *pvaOut)
2146 {
2147     add_call(&trace_got, 3, CmdGroup, (void*)(DWORD_PTR)nCmdID, (void*)(DWORD_PTR)nCmdexecopt, pvaIn, pvaOut);
2148     return S_OK;
2149 }
2150
2151 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl =
2152 {
2153     IOleCommandTargetImpl_QueryInterface,
2154     IOleCommandTargetImpl_AddRef,
2155     IOleCommandTargetImpl_Release,
2156     IOleCommandTargetImpl_QueryStatus,
2157     IOleCommandTargetImpl_Exec
2158 };
2159
2160 typedef struct {
2161     IServiceProvider IServiceProvider_iface;
2162     LONG ref;
2163 } IServiceProviderImpl;
2164
2165 static inline IServiceProviderImpl *impl_from_IServiceProvider(IServiceProvider *iface)
2166 {
2167     return CONTAINING_RECORD(iface, IServiceProviderImpl, IServiceProvider_iface);
2168 }
2169
2170 typedef struct {
2171     IProfferService IProfferService_iface;
2172     LONG ref;
2173 } IProfferServiceImpl;
2174
2175 static inline IProfferServiceImpl *impl_from_IProfferService(IProfferService *iface)
2176 {
2177     return CONTAINING_RECORD(iface, IProfferServiceImpl, IProfferService_iface);
2178 }
2179
2180
2181 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl;
2182 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl;
2183
2184 static IServiceProvider* IServiceProviderImpl_Construct(void)
2185 {
2186     IServiceProviderImpl *obj;
2187
2188     obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2189     obj->IServiceProvider_iface.lpVtbl = &IServiceProviderImpl_Vtbl;
2190     obj->ref = 1;
2191
2192     return &obj->IServiceProvider_iface;
2193 }
2194
2195 static IProfferService* IProfferServiceImpl_Construct(void)
2196 {
2197     IProfferServiceImpl *obj;
2198
2199     obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2200     obj->IProfferService_iface.lpVtbl = &IProfferServiceImpl_Vtbl;
2201     obj->ref = 1;
2202
2203     return &obj->IProfferService_iface;
2204 }
2205
2206 static HRESULT WINAPI IServiceProviderImpl_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppvObj)
2207 {
2208     IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
2209
2210     if (IsEqualIID(riid, &IID_IUnknown) ||
2211         IsEqualIID(riid, &IID_IServiceProvider))
2212     {
2213         *ppvObj = This;
2214     }
2215
2216     if(*ppvObj)
2217     {
2218         IServiceProvider_AddRef(iface);
2219         /* native uses redefined IID_IServiceProvider symbol, so we can't compare pointers */
2220         if (IsEqualIID(riid, &IID_IServiceProvider))
2221             add_call(&trace_got, 1, iface, &IID_IServiceProvider, 0, 0, 0);
2222         return S_OK;
2223     }
2224
2225     return E_NOINTERFACE;
2226 }
2227
2228 static ULONG WINAPI IServiceProviderImpl_AddRef(IServiceProvider *iface)
2229 {
2230     IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
2231     return InterlockedIncrement(&This->ref);
2232 }
2233
2234 static ULONG WINAPI IServiceProviderImpl_Release(IServiceProvider *iface)
2235 {
2236     IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
2237     ULONG ref = InterlockedDecrement(&This->ref);
2238
2239     if (!ref)
2240     {
2241         HeapFree(GetProcessHeap(), 0, This);
2242         return 0;
2243     }
2244     return ref;
2245 }
2246
2247 static HRESULT WINAPI IServiceProviderImpl_QueryService(
2248     IServiceProvider *iface, REFGUID service, REFIID riid, void **ppv)
2249 {
2250     /* native uses redefined pointer for IID_IOleCommandTarget, not one from uuid.lib */
2251     if (IsEqualIID(riid, &IID_IOleCommandTarget))
2252     {
2253         add_call(&trace_got, 2, iface, service, &IID_IOleCommandTarget, 0, 0);
2254         *ppv = IOleCommandTargetImpl_Construct();
2255     }
2256     if (IsEqualIID(riid, &IID_IProfferService))
2257     {
2258         if (IsEqualIID(service, &IID_IProfferService))
2259             add_call(&trace_got, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2260         *ppv = IProfferServiceImpl_Construct();
2261     }
2262     return S_OK;
2263 }
2264
2265 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl =
2266 {
2267     IServiceProviderImpl_QueryInterface,
2268     IServiceProviderImpl_AddRef,
2269     IServiceProviderImpl_Release,
2270     IServiceProviderImpl_QueryService
2271 };
2272
2273 static void test_IUnknown_QueryServiceExec(void)
2274 {
2275     IServiceProvider *provider = IServiceProviderImpl_Construct();
2276     static const GUID dummy_serviceid = { 0xdeadbeef };
2277     static const GUID dummy_groupid = { 0xbeefbeef };
2278     call_trace_t trace_expected;
2279     HRESULT hr;
2280
2281     /* on <=W2K platforms same ordinal used for another export with different
2282        prototype, so skipping using this indirect condition */
2283     if (is_win2k_and_lower)
2284     {
2285         win_skip("IUnknown_QueryServiceExec is not available\n");
2286         return;
2287     }
2288
2289     /* null source pointer */
2290     hr = pIUnknown_QueryServiceExec(NULL, &dummy_serviceid, &dummy_groupid, 0, 0, 0, 0);
2291     ok(hr == E_FAIL, "got 0x%08x\n", hr);
2292
2293     /* expected trace:
2294        IUnknown_QueryServiceExec( ptr1, serviceid, groupid, arg1, arg2, arg3, arg4);
2295          -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &prov );
2296          -> IServiceProvider_QueryService( prov, serviceid, &IID_IOleCommandTarget, &obj );
2297          -> IOleCommandTarget_Exec( obj, groupid, arg1, arg2, arg3, arg4 );
2298     */
2299     init_call_trace(&trace_expected);
2300
2301     add_call(&trace_expected, 1, provider, &IID_IServiceProvider, 0, 0, 0);
2302     add_call(&trace_expected, 2, provider, &dummy_serviceid, &IID_IOleCommandTarget, 0, 0);
2303     add_call(&trace_expected, 3, &dummy_groupid, (void*)0x1, (void*)0x2, (void*)0x3, (void*)0x4);
2304
2305     init_call_trace(&trace_got);
2306     hr = pIUnknown_QueryServiceExec((IUnknown*)provider, &dummy_serviceid, &dummy_groupid, 0x1, 0x2, (void*)0x3, (void*)0x4);
2307     ok(hr == S_OK, "got 0x%08x\n", hr);
2308
2309     ok_trace(&trace_expected, &trace_got);
2310
2311     free_call_trace(&trace_expected);
2312     free_call_trace(&trace_got);
2313
2314     IServiceProvider_Release(provider);
2315 }
2316
2317
2318 static HRESULT WINAPI IProfferServiceImpl_QueryInterface(IProfferService *iface, REFIID riid, void **ppvObj)
2319 {
2320     IProfferServiceImpl *This = impl_from_IProfferService(iface);
2321
2322     if (IsEqualIID(riid, &IID_IUnknown) ||
2323         IsEqualIID(riid, &IID_IProfferService))
2324     {
2325         *ppvObj = This;
2326     }
2327     else if (IsEqualIID(riid, &IID_IServiceProvider))
2328     {
2329         *ppvObj = IServiceProviderImpl_Construct();
2330         add_call(&trace_got, 1, iface, &IID_IServiceProvider, 0, 0, 0);
2331         return S_OK;
2332     }
2333
2334     if(*ppvObj)
2335     {
2336         IProfferService_AddRef(iface);
2337         return S_OK;
2338     }
2339
2340     return E_NOINTERFACE;
2341 }
2342
2343 static ULONG WINAPI IProfferServiceImpl_AddRef(IProfferService *iface)
2344 {
2345     IProfferServiceImpl *This = impl_from_IProfferService(iface);
2346     return InterlockedIncrement(&This->ref);
2347 }
2348
2349 static ULONG WINAPI IProfferServiceImpl_Release(IProfferService *iface)
2350 {
2351     IProfferServiceImpl *This = impl_from_IProfferService(iface);
2352     ULONG ref = InterlockedDecrement(&This->ref);
2353
2354     if (!ref)
2355     {
2356         HeapFree(GetProcessHeap(), 0, This);
2357         return 0;
2358     }
2359     return ref;
2360 }
2361
2362 static HRESULT WINAPI IProfferServiceImpl_ProfferService(IProfferService *iface,
2363     REFGUID service, IServiceProvider *pService, DWORD *pCookie)
2364 {
2365     *pCookie = 0xdeadbeef;
2366     add_call(&trace_got, 3, service, pService, pCookie, 0, 0);
2367     return S_OK;
2368 }
2369
2370 static HRESULT WINAPI IProfferServiceImpl_RevokeService(IProfferService *iface, DWORD cookie)
2371 {
2372     add_call(&trace_got, 4, (void*)(DWORD_PTR)cookie, 0, 0, 0, 0);
2373     return S_OK;
2374 }
2375
2376 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl =
2377 {
2378     IProfferServiceImpl_QueryInterface,
2379     IProfferServiceImpl_AddRef,
2380     IProfferServiceImpl_Release,
2381     IProfferServiceImpl_ProfferService,
2382     IProfferServiceImpl_RevokeService
2383 };
2384
2385 static void test_IUnknown_ProfferService(void)
2386 {
2387     IServiceProvider *provider = IServiceProviderImpl_Construct();
2388     IProfferService *proff = IProfferServiceImpl_Construct();
2389     static const GUID dummy_serviceid = { 0xdeadbeef };
2390     call_trace_t trace_expected;
2391     HRESULT hr;
2392     DWORD cookie;
2393
2394     /* on <=W2K platforms same ordinal used for another export with different
2395        prototype, so skipping using this indirect condition */
2396     if (is_win2k_and_lower)
2397     {
2398         win_skip("IUnknown_ProfferService is not available\n");
2399         return;
2400     }
2401
2402     /* null source pointer */
2403     hr = pIUnknown_ProfferService(NULL, &dummy_serviceid, 0, 0);
2404     ok(hr == E_FAIL, "got 0x%08x\n", hr);
2405
2406     /* expected trace:
2407        IUnknown_ProfferService( ptr1, serviceid, arg1, arg2);
2408          -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &provider );
2409          -> IServiceProvider_QueryService( provider, &IID_IProfferService, &IID_IProfferService, &proffer );
2410
2411          if (service pointer not null):
2412              -> IProfferService_ProfferService( proffer, serviceid, arg1, arg2 );
2413          else
2414              -> IProfferService_RevokeService( proffer, *arg2 );
2415     */
2416     init_call_trace(&trace_expected);
2417
2418     add_call(&trace_expected, 1, proff, &IID_IServiceProvider, 0, 0, 0);
2419     add_call(&trace_expected, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2420     add_call(&trace_expected, 3, &dummy_serviceid, provider, &cookie, 0, 0);
2421
2422     init_call_trace(&trace_got);
2423     cookie = 0;
2424     hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, provider, &cookie);
2425     ok(hr == S_OK, "got 0x%08x\n", hr);
2426     ok(cookie == 0xdeadbeef, "got %x\n", cookie);
2427
2428     ok_trace(&trace_expected, &trace_got);
2429     free_call_trace(&trace_got);
2430     free_call_trace(&trace_expected);
2431
2432     /* same with ::Revoke path */
2433     init_call_trace(&trace_expected);
2434
2435     add_call(&trace_expected, 1, proff, &IID_IServiceProvider, 0, 0, 0);
2436     add_call(&trace_expected, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2437     add_call(&trace_expected, 4, (void*)(DWORD_PTR)cookie, 0, 0, 0, 0);
2438
2439     init_call_trace(&trace_got);
2440     ok(cookie != 0, "got %x\n", cookie);
2441     hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, 0, &cookie);
2442     ok(hr == S_OK, "got 0x%08x\n", hr);
2443     ok(cookie == 0, "got %x\n", cookie);
2444     ok_trace(&trace_expected, &trace_got);
2445     free_call_trace(&trace_got);
2446     free_call_trace(&trace_expected);
2447
2448     IServiceProvider_Release(provider);
2449     IProfferService_Release(proff);
2450 }
2451
2452 static void test_SHCreateWorkerWindowA(void)
2453 {
2454     WNDCLASSA cliA;
2455     char classA[20];
2456     HWND hwnd;
2457     LONG_PTR ret;
2458     BOOL res;
2459
2460     if (is_win2k_and_lower)
2461     {
2462         win_skip("SHCreateWorkerWindowA not available\n");
2463         return;
2464     }
2465
2466     hwnd = pSHCreateWorkerWindowA(0, NULL, 0, 0, 0, 0);
2467     ok(hwnd != 0, "expected window\n");
2468
2469     GetClassName(hwnd, classA, 20);
2470     ok(lstrcmpA(classA, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA);
2471
2472     ret = GetWindowLongPtrA(hwnd, 0);
2473     ok(ret == 0, "got %ld\n", ret);
2474
2475     /* class info */
2476     memset(&cliA, 0, sizeof(cliA));
2477     res = GetClassInfoA(GetModuleHandle("shlwapi.dll"), "WorkerA", &cliA);
2478     ok(res, "failed to get class info\n");
2479     ok(cliA.style == 0, "got 0x%08x\n", cliA.style);
2480     ok(cliA.cbClsExtra == 0, "got %d\n", cliA.cbClsExtra);
2481     ok(cliA.cbWndExtra == sizeof(LONG_PTR), "got %d\n", cliA.cbWndExtra);
2482     ok(cliA.lpszMenuName == 0, "got %s\n", cliA.lpszMenuName);
2483
2484     DestroyWindow(hwnd);
2485
2486     /* set extra bytes */
2487     hwnd = pSHCreateWorkerWindowA(0, NULL, 0, 0, 0, 0xdeadbeef);
2488     ok(hwnd != 0, "expected window\n");
2489
2490     GetClassName(hwnd, classA, 20);
2491     ok(lstrcmpA(classA, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA);
2492
2493     ret = GetWindowLongPtrA(hwnd, 0);
2494     ok(ret == 0xdeadbeef, "got %ld\n", ret);
2495
2496     /* test exstyle */
2497     ret = GetWindowLongA(hwnd, GWL_EXSTYLE);
2498     ok(ret == WS_EX_WINDOWEDGE ||
2499        ret == (WS_EX_WINDOWEDGE|WS_EX_LAYOUTRTL) /* systems with RTL locale */, "0x%08lx\n", ret);
2500
2501     DestroyWindow(hwnd);
2502
2503     hwnd = pSHCreateWorkerWindowA(0, NULL, WS_EX_TOOLWINDOW, 0, 0, 0);
2504     ret = GetWindowLongA(hwnd, GWL_EXSTYLE);
2505     ok(ret == (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW) ||
2506        ret == (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW|WS_EX_LAYOUTRTL) /* systems with RTL locale */, "0x%08lx\n", ret);
2507     DestroyWindow(hwnd);
2508 }
2509
2510 static HRESULT WINAPI SF_QueryInterface(IShellFolder *iface,
2511         REFIID riid, void **ppv)
2512 {
2513     /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */
2514     ok(!IsEqualGUID(&IID_IShellFolder, riid),
2515             "Unexpected QI for IShellFolder\n");
2516     return E_NOINTERFACE;
2517 }
2518
2519 static ULONG WINAPI SF_AddRef(IShellFolder *iface)
2520 {
2521     return 2;
2522 }
2523
2524 static ULONG WINAPI SF_Release(IShellFolder *iface)
2525 {
2526     return 1;
2527 }
2528
2529 static HRESULT WINAPI SF_ParseDisplayName(IShellFolder *iface,
2530         HWND owner, LPBC reserved, LPOLESTR displayName, ULONG *eaten,
2531         LPITEMIDLIST *idl, ULONG *attr)
2532 {
2533     ok(0, "Didn't expect ParseDisplayName\n");
2534     return E_NOTIMPL;
2535 }
2536
2537 static HRESULT WINAPI SF_EnumObjects(IShellFolder *iface,
2538         HWND owner, SHCONTF flags, IEnumIDList **enm)
2539 {
2540     *enm = (IEnumIDList*)0xcafebabe;
2541     return S_OK;
2542 }
2543
2544 static HRESULT WINAPI SF_BindToObject(IShellFolder *iface,
2545         LPCITEMIDLIST idl, LPBC reserved, REFIID riid, void **obj)
2546 {
2547     ok(0, "Didn't expect BindToObject\n");
2548     return E_NOTIMPL;
2549 }
2550
2551 static HRESULT WINAPI SF_BindToStorage(IShellFolder *iface,
2552         LPCITEMIDLIST idl, LPBC reserved, REFIID riid, void **obj)
2553 {
2554     ok(0, "Didn't expect BindToStorage\n");
2555     return E_NOTIMPL;
2556 }
2557
2558 static HRESULT WINAPI SF_CompareIDs(IShellFolder *iface,
2559         LPARAM lparam, LPCITEMIDLIST idl1, LPCITEMIDLIST idl2)
2560 {
2561     ok(0, "Didn't expect CompareIDs\n");
2562     return E_NOTIMPL;
2563 }
2564
2565 static HRESULT WINAPI SF_CreateViewObject(IShellFolder *iface,
2566         HWND owner, REFIID riid, void **out)
2567 {
2568     ok(0, "Didn't expect CreateViewObject\n");
2569     return E_NOTIMPL;
2570 }
2571
2572 static HRESULT WINAPI SF_GetAttributesOf(IShellFolder *iface,
2573         UINT cidl, LPCITEMIDLIST *idl, SFGAOF *inOut)
2574 {
2575     ok(0, "Didn't expect GetAttributesOf\n");
2576     return E_NOTIMPL;
2577 }
2578
2579 static HRESULT WINAPI SF_GetUIObjectOf(IShellFolder *iface,
2580         HWND owner, UINT cidl, LPCITEMIDLIST *idls, REFIID riid, UINT *inOut,
2581         void **out)
2582 {
2583     ok(0, "Didn't expect GetUIObjectOf\n");
2584     return E_NOTIMPL;
2585 }
2586
2587 static HRESULT WINAPI SF_GetDisplayNameOf(IShellFolder *iface,
2588         LPCITEMIDLIST idl, SHGDNF flags, STRRET *name)
2589 {
2590     ok(0, "Didn't expect GetDisplayNameOf\n");
2591     return E_NOTIMPL;
2592 }
2593
2594 static HRESULT WINAPI SF_SetNameOf(IShellFolder *iface,
2595         HWND hwnd, LPCITEMIDLIST idl, LPCOLESTR name, SHGDNF flags,
2596         LPITEMIDLIST *idlOut)
2597 {
2598     ok(0, "Didn't expect SetNameOf\n");
2599     return E_NOTIMPL;
2600 }
2601
2602 static IShellFolderVtbl ShellFolderVtbl = {
2603     SF_QueryInterface,
2604     SF_AddRef,
2605     SF_Release,
2606     SF_ParseDisplayName,
2607     SF_EnumObjects,
2608     SF_BindToObject,
2609     SF_BindToStorage,
2610     SF_CompareIDs,
2611     SF_CreateViewObject,
2612     SF_GetAttributesOf,
2613     SF_GetUIObjectOf,
2614     SF_GetDisplayNameOf,
2615     SF_SetNameOf
2616 };
2617
2618 static IShellFolder ShellFolder = { &ShellFolderVtbl };
2619
2620 static void test_SHIShellFolder_EnumObjects(void)
2621 {
2622     IEnumIDList *enm;
2623     HRESULT hres;
2624     IShellFolder *folder;
2625
2626     if(!pSHIShellFolder_EnumObjects || is_win2k_and_lower){
2627         win_skip("SHIShellFolder_EnumObjects not available\n");
2628         return;
2629     }
2630
2631     if(0){
2632         /* NULL object crashes on Windows */
2633         pSHIShellFolder_EnumObjects(NULL, NULL, 0, NULL);
2634     }
2635
2636     /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */
2637     enm = (IEnumIDList*)0xdeadbeef;
2638     hres = pSHIShellFolder_EnumObjects(&ShellFolder, NULL, 0, &enm);
2639     ok(hres == S_OK, "SHIShellFolder_EnumObjects failed: 0x%08x\n", hres);
2640     ok(enm == (IEnumIDList*)0xcafebabe, "Didn't get expected enumerator location, instead: %p\n", enm);
2641
2642     /* SHIShellFolder_EnumObjects isn't strict about the IShellFolder object */
2643     hres = pSHGetDesktopFolder(&folder);
2644     ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
2645
2646     enm = NULL;
2647     hres = pSHIShellFolder_EnumObjects(folder, NULL, 0, &enm);
2648     ok(hres == S_OK, "SHIShellFolder_EnumObjects failed: 0x%08x\n", hres);
2649     ok(enm != NULL, "Didn't get an enumerator\n");
2650     if(enm)
2651         IEnumIDList_Release(enm);
2652
2653     IShellFolder_Release(folder);
2654 }
2655
2656 static void write_inifile(LPCWSTR filename)
2657 {
2658     DWORD written;
2659     HANDLE file;
2660
2661     static const char data[] =
2662         "[TestApp]\r\n"
2663         "AKey=1\r\n"
2664         "AnotherKey=asdf\r\n";
2665
2666     file = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
2667     if(file == INVALID_HANDLE_VALUE)
2668         return;
2669
2670     WriteFile(file, data, sizeof(data), &written, NULL);
2671
2672     CloseHandle(file);
2673 }
2674
2675 #define verify_inifile(f, e) r_verify_inifile(__LINE__, f, e)
2676 static void r_verify_inifile(unsigned l, LPCWSTR filename, LPCSTR exp)
2677 {
2678     HANDLE file;
2679     CHAR buf[1024];
2680     DWORD read;
2681
2682     file = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
2683     if(file == INVALID_HANDLE_VALUE)
2684         return;
2685
2686     ReadFile(file, buf, sizeof(buf) * sizeof(CHAR), &read, NULL);
2687     buf[read] = '\0';
2688
2689     CloseHandle(file);
2690
2691     ok_(__FILE__,l)(!strcmp(buf, exp), "Expected:\n%s\nGot:\n%s\n", exp,
2692             buf);
2693 }
2694
2695 static void test_SHGetIniString(void)
2696 {
2697     DWORD ret;
2698     WCHAR out[64] = {0};
2699
2700     static const WCHAR TestAppW[] = {'T','e','s','t','A','p','p',0};
2701     static const WCHAR TestIniW[] = {'C',':','\\','t','e','s','t','.','i','n','i',0};
2702     static const WCHAR AKeyW[] = {'A','K','e','y',0};
2703     static const WCHAR AnotherKeyW[] = {'A','n','o','t','h','e','r','K','e','y',0};
2704     static const WCHAR JunkKeyW[] = {'J','u','n','k','K','e','y',0};
2705
2706     if(!pSHGetIniStringW || is_win2k_and_lower){
2707         win_skip("SHGetIniStringW is not available\n");
2708         return;
2709     }
2710
2711     write_inifile(TestIniW);
2712
2713     if(0){
2714         /* these crash on Windows */
2715         pSHGetIniStringW(NULL, NULL, NULL, 0, NULL);
2716         pSHGetIniStringW(NULL, AKeyW, out, sizeof(out), TestIniW);
2717         pSHGetIniStringW(TestAppW, AKeyW, NULL, sizeof(out), TestIniW);
2718     }
2719
2720     ret = pSHGetIniStringW(TestAppW, AKeyW, out, 0, TestIniW);
2721     ok(ret == 0, "SHGetIniStringW should have given 0, instead: %d\n", ret);
2722
2723     /* valid arguments */
2724     ret = pSHGetIniStringW(TestAppW, NULL, out, sizeof(out), TestIniW);
2725     ok(broken(ret == 0) || /* win 98 */
2726             ret == 4, "SHGetIniStringW should have given 4, instead: %d\n", ret);
2727     ok(!lstrcmpW(out, AKeyW), "Expected %s, got: %s\n",
2728                 wine_dbgstr_w(AKeyW), wine_dbgstr_w(out));
2729
2730     ret = pSHGetIniStringW(TestAppW, AKeyW, out, sizeof(out), TestIniW);
2731     ok(broken(ret == 0) || /* win 98 */
2732                 ret == 1, "SHGetIniStringW should have given 1, instead: %d\n", ret);
2733     ok(broken(*out == 0) || /*win 98 */
2734         !strcmp_wa(out, "1"), "Expected L\"1\", got: %s\n", wine_dbgstr_w(out));
2735
2736     ret = pSHGetIniStringW(TestAppW, AnotherKeyW, out, sizeof(out), TestIniW);
2737     ok(broken(ret == 0) || /* win 98 */
2738             ret == 4, "SHGetIniStringW should have given 4, instead: %d\n", ret);
2739     ok(broken(*out == 0) || /* win 98 */
2740             !strcmp_wa(out, "asdf"), "Expected L\"asdf\", got: %s\n", wine_dbgstr_w(out));
2741
2742     ret = pSHGetIniStringW(TestAppW, JunkKeyW, out, sizeof(out), TestIniW);
2743     ok(ret == 0, "SHGetIniStringW should have given 0, instead: %d\n", ret);
2744     ok(*out == 0, "Expected L\"\", got: %s\n", wine_dbgstr_w(out));
2745
2746     DeleteFileW(TestIniW);
2747 }
2748
2749 static void test_SHSetIniString(void)
2750 {
2751     BOOL ret;
2752
2753     static const WCHAR TestAppW[] = {'T','e','s','t','A','p','p',0};
2754     static const WCHAR AnotherAppW[] = {'A','n','o','t','h','e','r','A','p','p',0};
2755     static const WCHAR TestIniW[] = {'C',':','\\','t','e','s','t','.','i','n','i',0};
2756     static const WCHAR AKeyW[] = {'A','K','e','y',0};
2757     static const WCHAR NewKeyW[] = {'N','e','w','K','e','y',0};
2758     static const WCHAR AValueW[] = {'A','V','a','l','u','e',0};
2759
2760     if(!pSHSetIniStringW || is_win2k_and_lower){
2761         win_skip("SHSetIniStringW is not available\n");
2762         return;
2763     }
2764
2765     write_inifile(TestIniW);
2766
2767     ret = pSHSetIniStringW(TestAppW, AKeyW, AValueW, TestIniW);
2768     ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2769     todo_wine /* wine sticks an extra \r\n at the end of the file */
2770         verify_inifile(TestIniW, "[TestApp]\r\nAKey=AValue\r\nAnotherKey=asdf\r\n");
2771
2772     ret = pSHSetIniStringW(TestAppW, AKeyW, NULL, TestIniW);
2773     ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2774     verify_inifile(TestIniW, "[TestApp]\r\nAnotherKey=asdf\r\n");
2775
2776     ret = pSHSetIniStringW(AnotherAppW, NewKeyW, AValueW, TestIniW);
2777     ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2778     verify_inifile(TestIniW, "[TestApp]\r\nAnotherKey=asdf\r\n[AnotherApp]\r\nNewKey=AValue\r\n");
2779
2780     ret = pSHSetIniStringW(TestAppW, NULL, AValueW, TestIniW);
2781     ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2782     verify_inifile(TestIniW, "[AnotherApp]\r\nNewKey=AValue\r\n");
2783
2784     DeleteFileW(TestIniW);
2785 }
2786
2787 enum _shellkey_flags {
2788     SHKEY_Root_HKCU = 0x1,
2789     SHKEY_Root_HKLM = 0x2,
2790     SHKEY_Key_Explorer  = 0x00,
2791     SHKEY_Key_Shell = 0x10,
2792     SHKEY_Key_ShellNoRoam = 0x20,
2793     SHKEY_Key_Classes = 0x30,
2794     SHKEY_Subkey_Default = 0x0000,
2795     SHKEY_Subkey_ResourceName = 0x1000,
2796     SHKEY_Subkey_Handlers = 0x2000,
2797     SHKEY_Subkey_Associations = 0x3000,
2798     SHKEY_Subkey_Volatile = 0x4000,
2799     SHKEY_Subkey_MUICache = 0x5000,
2800     SHKEY_Subkey_FileExts = 0x6000
2801 };
2802
2803 static void test_SHGetShellKey(void)
2804 {
2805     static const WCHAR ShellFoldersW[] = { 'S','h','e','l','l',' ','F','o','l','d','e','r','s',0 };
2806     static const WCHAR WineTestW[] = { 'W','i','n','e','T','e','s','t',0 };
2807
2808     void *pPathBuildRootW = GetProcAddress(hShlwapi, "PathBuildRootW");
2809     DWORD *alloc_data, data, size;
2810     HKEY hkey;
2811     HRESULT hres;
2812
2813     if (!pSHGetShellKey)
2814     {
2815         win_skip("SHGetShellKey(ordinal 491) isn't available\n");
2816         return;
2817     }
2818
2819     /* some win2k */
2820     if (pPathBuildRootW && pPathBuildRootW == pSHGetShellKey)
2821     {
2822         win_skip("SHGetShellKey(ordinal 491) used for PathBuildRootW\n");
2823         return;
2824     }
2825
2826     if (is_win9x || is_win2k_and_lower)
2827     {
2828         win_skip("Ordinal 491 used for another call, skipping SHGetShellKey tests\n");
2829         return;
2830     }
2831
2832     /* Vista+ limits SHKEY enumeration values */
2833     SetLastError(0xdeadbeef);
2834     hkey = pSHGetShellKey(SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2835     if (hkey)
2836     {
2837         /* Tests not working on Vista+ */
2838         RegCloseKey(hkey);
2839
2840         hkey = pSHGetShellKey(SHKEY_Root_HKLM|SHKEY_Key_Classes, NULL, FALSE);
2841         ok(hkey != NULL, "hkey = NULL\n");
2842         RegCloseKey(hkey);
2843     }
2844
2845     hkey = pSHGetShellKey(SHKEY_Root_HKCU|SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2846     ok(hkey != NULL, "hkey = NULL\n");
2847     RegCloseKey(hkey);
2848
2849     hkey = pSHGetShellKey(SHKEY_Root_HKLM|SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2850     ok(hkey != NULL, "hkey = NULL\n");
2851     RegCloseKey(hkey);
2852
2853     hkey = pSHGetShellKey(SHKEY_Root_HKLM, WineTestW, FALSE);
2854     ok(hkey == NULL, "hkey != NULL\n");
2855
2856     hkey = pSHGetShellKey(SHKEY_Root_HKLM, NULL, FALSE);
2857     ok(hkey != NULL, "Can't open key\n");
2858     ok(SUCCEEDED(RegDeleteKeyW(hkey, WineTestW)), "Can't delete key\n");
2859     RegCloseKey(hkey);
2860
2861     hkey = pSHGetShellKey(SHKEY_Root_HKLM, WineTestW, TRUE);
2862     if (!hkey && GetLastError() == ERROR_ACCESS_DENIED)
2863     {
2864         skip("Not authorized to create keys\n");
2865         return;
2866     }
2867     ok(hkey != NULL, "Can't create key\n");
2868     RegCloseKey(hkey);
2869
2870     if (!pSKGetValueW || !pSKSetValueW || !pSKDeleteValueW || !pSKAllocValueW)
2871     {
2872         win_skip("SKGetValueW, SKSetValueW, SKDeleteValueW or SKAllocValueW not available\n");
2873         return;
2874     }
2875
2876     size = sizeof(data);
2877     hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
2878     ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres);
2879
2880     data = 1234;
2881     hres = pSKSetValueW(SHKEY_Root_HKLM, WineTestW, NULL, REG_DWORD, &data, sizeof(DWORD));
2882     ok(hres == S_OK, "hres = %x\n", hres);
2883
2884     size = 1;
2885     hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, NULL, &size);
2886     ok(hres == S_OK, "hres = %x\n", hres);
2887     ok(size == sizeof(DWORD), "size = %d\n", size);
2888
2889     data = 0xdeadbeef;
2890     hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
2891     ok(hres == S_OK, "hres = %x\n", hres);
2892     ok(size == sizeof(DWORD), "size = %d\n", size);
2893     ok(data == 1234, "data = %d\n", data);
2894
2895     hres = pSKAllocValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, (void**)&alloc_data, &size);
2896     ok(hres == S_OK, "hres= %x\n", hres);
2897     ok(size == sizeof(DWORD), "size = %d\n", size);
2898     if (SUCCEEDED(hres))
2899     {
2900         ok(*alloc_data == 1234, "*alloc_data = %d\n", *alloc_data);
2901         LocalFree(alloc_data);
2902     }
2903
2904     hres = pSKDeleteValueW(SHKEY_Root_HKLM, WineTestW, NULL);
2905     ok(hres == S_OK, "hres = %x\n", hres);
2906
2907     hres = pSKDeleteValueW(SHKEY_Root_HKLM, WineTestW, NULL);
2908     ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres);
2909
2910     hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
2911     ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres);
2912
2913     hkey = pSHGetShellKey(SHKEY_Root_HKLM, NULL, FALSE);
2914     ok(hkey != NULL, "Can't create key\n");
2915     ok(SUCCEEDED(RegDeleteKeyW(hkey, WineTestW)), "Can't delete key\n");
2916     RegCloseKey(hkey);
2917 }
2918
2919 static void init_pointers(void)
2920 {
2921 #define MAKEFUNC(f, ord) (p##f = (void*)GetProcAddress(hShlwapi, (LPSTR)(ord)))
2922     MAKEFUNC(SHAllocShared, 7);
2923     MAKEFUNC(SHLockShared, 8);
2924     MAKEFUNC(SHUnlockShared, 9);
2925     MAKEFUNC(SHFreeShared, 10);
2926     MAKEFUNC(GetAcceptLanguagesA, 14);
2927     MAKEFUNC(SHSetWindowBits, 165);
2928     MAKEFUNC(SHSetParentHwnd, 167);
2929     MAKEFUNC(ConnectToConnectionPoint, 168);
2930     MAKEFUNC(SHSearchMapInt, 198);
2931     MAKEFUNC(SHCreateWorkerWindowA, 257);
2932     MAKEFUNC(GUIDFromStringA, 269);
2933     MAKEFUNC(SHPackDispParams, 282);
2934     MAKEFUNC(IConnectionPoint_InvokeWithCancel, 283);
2935     MAKEFUNC(IConnectionPoint_SimpleInvoke, 284);
2936     MAKEFUNC(SHGetIniStringW, 294);
2937     MAKEFUNC(SHSetIniStringW, 295);
2938     MAKEFUNC(SHFormatDateTimeA, 353);
2939     MAKEFUNC(SHFormatDateTimeW, 354);
2940     MAKEFUNC(SHIShellFolder_EnumObjects, 404);
2941     MAKEFUNC(SHGetObjectCompatFlags, 476);
2942     MAKEFUNC(IUnknown_QueryServiceExec, 484);
2943     MAKEFUNC(SHGetShellKey, 491);
2944     MAKEFUNC(SHPropertyBag_ReadLONG, 496);
2945     MAKEFUNC(IUnknown_ProfferService, 514);
2946     MAKEFUNC(SKGetValueW, 516);
2947     MAKEFUNC(SKSetValueW, 517);
2948     MAKEFUNC(SKDeleteValueW, 518);
2949     MAKEFUNC(SKAllocValueW, 519);
2950 #undef MAKEFUNC
2951 }
2952
2953 static void test_SHSetParentHwnd(void)
2954 {
2955     HWND hwnd, hwnd2, ret;
2956     DWORD style;
2957
2958     if (!pSHSetParentHwnd)
2959     {
2960         win_skip("SHSetParentHwnd not available\n");
2961         return;
2962     }
2963
2964     hwnd = CreateWindowA("Button", "", WS_VISIBLE, 0, 0, 10, 10, NULL, NULL, NULL, NULL);
2965     ok(hwnd != NULL, "got %p\n", hwnd);
2966
2967     hwnd2 = CreateWindowA("Button", "", WS_VISIBLE | WS_CHILD, 0, 0, 10, 10, hwnd, NULL, NULL, NULL);
2968     ok(hwnd2 != NULL, "got %p\n", hwnd2);
2969
2970     /* null params */
2971     ret = pSHSetParentHwnd(NULL, NULL);
2972     ok(ret == NULL, "got %p\n", ret);
2973
2974     /* set to no parent while already no parent present */
2975     ret = GetParent(hwnd);
2976     ok(ret == NULL, "got %p\n", ret);
2977     style = GetWindowLongA(hwnd, GWL_STYLE);
2978     ok((style & (WS_POPUP|WS_CHILD)) == 0, "got style 0x%08x\n", style);
2979     ret = pSHSetParentHwnd(hwnd, NULL);
2980     ok(ret == NULL, "got %p\n", ret);
2981     style = GetWindowLongA(hwnd, GWL_STYLE);
2982     ok((style & (WS_POPUP|WS_CHILD)) == 0, "got style 0x%08x\n", style);
2983
2984     /* reset to null parent from not null */
2985     ret = GetParent(hwnd2);
2986     ok(ret == hwnd, "got %p\n", ret);
2987     style = GetWindowLongA(hwnd2, GWL_STYLE);
2988     ok((style & (WS_POPUP|WS_CHILD)) == WS_CHILD, "got style 0x%08x\n", style);
2989     ret = pSHSetParentHwnd(hwnd2, NULL);
2990     ok(ret == NULL, "got %p\n", ret);
2991     style = GetWindowLongA(hwnd2, GWL_STYLE);
2992     ok((style & (WS_POPUP|WS_CHILD)) == WS_POPUP, "got style 0x%08x\n", style);
2993     ret = GetParent(hwnd2);
2994     ok(ret == NULL, "got %p\n", ret);
2995
2996     /* set parent back */
2997     style = GetWindowLongA(hwnd2, GWL_STYLE);
2998     SetWindowLongA(hwnd2, GWL_STYLE, style & ~(WS_CHILD|WS_POPUP));
2999     style = GetWindowLongA(hwnd2, GWL_STYLE);
3000     ok((style & (WS_CHILD|WS_POPUP)) == 0, "got 0x%08x\n", style);
3001
3002     ret = pSHSetParentHwnd(hwnd2, hwnd);
3003     todo_wine ok(ret == NULL, "got %p\n", ret);
3004
3005     style = GetWindowLongA(hwnd2, GWL_STYLE);
3006     ok((style & (WS_POPUP|WS_CHILD)) == WS_CHILD, "got style 0x%08x\n", style);
3007     ret = GetParent(hwnd2);
3008     ok(ret == hwnd, "got %p\n", ret);
3009
3010     /* try to set same parent again */
3011     /* with WS_POPUP */
3012     style = GetWindowLongA(hwnd2, GWL_STYLE);
3013     SetWindowLongA(hwnd2, GWL_STYLE, style | WS_POPUP);
3014     ret = pSHSetParentHwnd(hwnd2, hwnd);
3015     todo_wine ok(ret == NULL, "got %p\n", ret);
3016     style = GetWindowLongA(hwnd2, GWL_STYLE);
3017     ok((style & (WS_CHILD|WS_POPUP)) == WS_CHILD, "got 0x%08x\n", style);
3018     ret = GetParent(hwnd2);
3019     ok(ret == hwnd, "got %p\n", ret);
3020
3021     /* without WS_POPUP */
3022     style = GetWindowLongA(hwnd2, GWL_STYLE);
3023     SetWindowLongA(hwnd2, GWL_STYLE, style | ~WS_POPUP);
3024     ret = pSHSetParentHwnd(hwnd2, hwnd);
3025     todo_wine ok(ret == hwnd, "got %p\n", ret);
3026     style = GetWindowLongA(hwnd2, GWL_STYLE);
3027     ok((style & (WS_CHILD|WS_POPUP)) == WS_CHILD, "got 0x%08x\n", style);
3028     ret = GetParent(hwnd2);
3029     ok(ret == hwnd, "got %p\n", ret);
3030
3031     DestroyWindow(hwnd);
3032     DestroyWindow(hwnd2);
3033 }
3034
3035 START_TEST(ordinal)
3036 {
3037     hShlwapi = GetModuleHandleA("shlwapi.dll");
3038     is_win2k_and_lower = GetProcAddress(hShlwapi, "StrChrNW") == 0;
3039     is_win9x = GetProcAddress(hShlwapi, (LPSTR)99) == 0; /* StrCpyNXA */
3040
3041     /* SHCreateStreamOnFileEx was introduced in shlwapi v6.0 */
3042     if(!GetProcAddress(hShlwapi, "SHCreateStreamOnFileEx")){
3043         win_skip("Too old shlwapi version\n");
3044         return;
3045     }
3046
3047     init_pointers();
3048
3049     hmlang = LoadLibraryA("mlang.dll");
3050     pLcidToRfc1766A = (void *)GetProcAddress(hmlang, "LcidToRfc1766A");
3051
3052     hshell32 = LoadLibraryA("shell32.dll");
3053     pSHGetDesktopFolder = (void *)GetProcAddress(hshell32, "SHGetDesktopFolder");
3054
3055     test_GetAcceptLanguagesA();
3056     test_SHSearchMapInt();
3057     test_alloc_shared();
3058     test_fdsa();
3059     test_GetShellSecurityDescriptor();
3060     test_SHPackDispParams();
3061     test_IConnectionPoint();
3062     test_SHPropertyBag_ReadLONG();
3063     test_SHSetWindowBits();
3064     test_SHFormatDateTimeA();
3065     test_SHFormatDateTimeW();
3066     test_SHGetObjectCompatFlags();
3067     test_IUnknown_QueryServiceExec();
3068     test_IUnknown_ProfferService();
3069     test_SHCreateWorkerWindowA();
3070     test_SHIShellFolder_EnumObjects();
3071     test_SHGetIniString();
3072     test_SHSetIniString();
3073     test_SHGetShellKey();
3074     test_SHSetParentHwnd();
3075
3076     FreeLibrary(hshell32);
3077     FreeLibrary(hmlang);
3078 }