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