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