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