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