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