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