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