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