shlwapi/tests: Fix some test failures on Vista+.
[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
33 /* Function ptrs for ordinal calls */
34 static HMODULE hShlwapi;
35 static int (WINAPI *pSHSearchMapInt)(const int*,const int*,int,int);
36 static HRESULT (WINAPI *pGetAcceptLanguagesA)(LPSTR,LPDWORD);
37
38 static HANDLE (WINAPI *pSHAllocShared)(LPCVOID,DWORD,DWORD);
39 static LPVOID (WINAPI *pSHLockShared)(HANDLE,DWORD);
40 static BOOL   (WINAPI *pSHUnlockShared)(LPVOID);
41 static BOOL   (WINAPI *pSHFreeShared)(HANDLE,DWORD);
42 static HRESULT(WINAPIV *pSHPackDispParams)(DISPPARAMS*,VARIANTARG*,UINT,...);
43 static HRESULT(WINAPI *pIConnectionPoint_SimpleInvoke)(IConnectionPoint*,DISPID,DISPPARAMS*);
44 static HRESULT(WINAPI *pIConnectionPoint_InvokeWithCancel)(IConnectionPoint*,DISPID,DISPPARAMS*,DWORD,DWORD);
45 static HRESULT(WINAPI *pConnectToConnectionPoint)(IUnknown*,REFIID,BOOL,IUnknown*, LPDWORD,IConnectionPoint **);
46 static HRESULT(WINAPI *pSHPropertyBag_ReadLONG)(IPropertyBag *,LPCWSTR,LPLONG);
47 static LONG   (WINAPI *pSHSetWindowBits)(HWND, INT, UINT, UINT);
48 static INT    (WINAPI *pSHFormatDateTimeA)(const FILETIME UNALIGNED*, DWORD*, LPSTR, UINT);
49 static INT    (WINAPI *pSHFormatDateTimeW)(const FILETIME UNALIGNED*, DWORD*, LPWSTR, UINT);
50 static DWORD  (WINAPI *pSHGetObjectCompatFlags)(IUnknown*, const CLSID*);
51 static BOOL   (WINAPI *pGUIDFromStringA)(LPSTR, CLSID *);
52
53 static HMODULE hmlang;
54 static HRESULT (WINAPI *pLcidToRfc1766A)(LCID, LPSTR, INT);
55
56 static const CHAR ie_international[] = {
57     'S','o','f','t','w','a','r','e','\\',
58     'M','i','c','r','o','s','o','f','t','\\',
59     'I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r','\\',
60     'I','n','t','e','r','n','a','t','i','o','n','a','l',0};
61 static const CHAR acceptlanguage[] = {
62     'A','c','c','e','p','t','L','a','n','g','u','a','g','e',0};
63
64
65 static void test_GetAcceptLanguagesA(void)
66 {
67     static LPCSTR table[] = {"de,en-gb;q=0.7,en;q=0.3",
68                              "de,en;q=0.3,en-gb;q=0.7", /* sorting is ignored */
69                              "winetest",    /* content is ignored */
70                              "de-de,de;q=0.5",
71                              "de",
72                              NULL};
73
74     DWORD exactsize;
75     char original[512];
76     char language[32];
77     char buffer[64];
78     HKEY hroot = NULL;
79     LONG res_query = ERROR_SUCCESS;
80     LONG lres;
81     HRESULT hr;
82     DWORD maxlen = sizeof(buffer) - 2;
83     DWORD len;
84     LCID lcid;
85     LPCSTR entry;
86     INT i = 0;
87
88     if (!pGetAcceptLanguagesA) {
89         win_skip("GetAcceptLanguagesA is not available\n");
90         return;
91     }
92
93     lcid = GetUserDefaultLCID();
94
95     /* Get the original Value */
96     lres = RegOpenKeyA(HKEY_CURRENT_USER, ie_international, &hroot);
97     if (lres) {
98         skip("RegOpenKey(%s) failed: %d\n", ie_international, lres);
99         return;
100     }
101     len = sizeof(original);
102     original[0] = 0;
103     res_query = RegQueryValueExA(hroot, acceptlanguage, 0, NULL, (PBYTE)original, &len);
104
105     RegDeleteValue(hroot, acceptlanguage);
106
107     /* Some windows versions use "lang-COUNTRY" as default */
108     memset(language, 0, sizeof(language));
109     len = GetLocaleInfoA(lcid, LOCALE_SISO639LANGNAME, language, sizeof(language));
110
111     if (len) {
112         lstrcat(language, "-");
113         memset(buffer, 0, sizeof(buffer));
114         len = GetLocaleInfoA(lcid, LOCALE_SISO3166CTRYNAME, buffer, sizeof(buffer) - len - 1);
115         lstrcat(language, buffer);
116     }
117     else
118     {
119         /* LOCALE_SNAME has additional parts in some languages. Try only as last chance */
120         memset(language, 0, sizeof(language));
121         len = GetLocaleInfoA(lcid, LOCALE_SNAME, language, sizeof(language));
122     }
123
124     /* get the default value */
125     len = maxlen;
126     memset(buffer, '#', maxlen);
127     buffer[maxlen] = 0;
128     hr = pGetAcceptLanguagesA( buffer, &len);
129
130     if (hr != S_OK) {
131         win_skip("GetAcceptLanguagesA failed with 0x%x\n", hr);
132         goto restore_original;
133     }
134
135     if (lstrcmpA(buffer, language)) {
136         /* some windows versions use "lang" or "lang-country" as default */
137         language[0] = 0;
138         if (pLcidToRfc1766A) {
139             hr = pLcidToRfc1766A(lcid, language, sizeof(language));
140             ok(hr == S_OK, "LcidToRfc1766A returned 0x%x and %s\n", hr, language);
141         }
142     }
143
144     ok(!lstrcmpA(buffer, language),
145         "have '%s' (searching for '%s')\n", language, buffer);
146
147     if (lstrcmpA(buffer, language)) {
148         win_skip("no more ideas, how to build the default language '%s'\n", buffer);
149         goto restore_original;
150     }
151
152     trace("detected default: %s\n", language);
153     while ((entry = table[i])) {
154
155         exactsize = lstrlenA(entry);
156
157         lres = RegSetValueExA(hroot, acceptlanguage, 0, REG_SZ, (const BYTE *) entry, exactsize + 1);
158         ok(!lres, "got %d for RegSetValueExA: %s\n", lres, entry);
159
160         /* len includes space for the terminating 0 before vista/w2k8 */
161         len = exactsize + 2;
162         memset(buffer, '#', maxlen);
163         buffer[maxlen] = 0;
164         hr = pGetAcceptLanguagesA( buffer, &len);
165         ok(((hr == E_INVALIDARG) && (len == 0)) ||
166             (SUCCEEDED(hr) &&
167             ((len == exactsize) || (len == exactsize+1)) &&
168             !lstrcmpA(buffer, entry)),
169             "+2_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
170
171         len = exactsize + 1;
172         memset(buffer, '#', maxlen);
173         buffer[maxlen] = 0;
174         hr = pGetAcceptLanguagesA( buffer, &len);
175         ok(((hr == E_INVALIDARG) && (len == 0)) ||
176             (SUCCEEDED(hr) &&
177             ((len == exactsize) || (len == exactsize+1)) &&
178             !lstrcmpA(buffer, entry)),
179             "+1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
180
181         len = exactsize;
182         memset(buffer, '#', maxlen);
183         buffer[maxlen] = 0;
184         hr = pGetAcceptLanguagesA( buffer, &len);
185
186         /* There is no space for the string in the registry.
187            When the buffer is large enough, the default language is returned
188
189            When the buffer is to small for that fallback, win7_32 and w2k8_64
190            and above fail with HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), but
191            recent os succeed and return a partial result while
192            older os succeed and overflow the buffer */
193
194         ok(((hr == E_INVALIDARG) && (len == 0)) ||
195             (((hr == S_OK) && !lstrcmpA(buffer, language)  && (len == lstrlenA(language))) ||
196             ((hr == S_OK) && !memcmp(buffer, language, len)) ||
197             ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len)),
198             "==_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
199
200         if (exactsize > 1) {
201             len = exactsize - 1;
202             memset(buffer, '#', maxlen);
203             buffer[maxlen] = 0;
204             hr = pGetAcceptLanguagesA( buffer, &len);
205             ok(((hr == E_INVALIDARG) && (len == 0)) ||
206                 (((hr == S_OK) && !lstrcmpA(buffer, language)  && (len == lstrlenA(language))) ||
207                 ((hr == S_OK) && !memcmp(buffer, language, len)) ||
208                 ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len)),
209                 "-1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
210         }
211
212         len = 1;
213         memset(buffer, '#', maxlen);
214         buffer[maxlen] = 0;
215         hr = pGetAcceptLanguagesA( buffer, &len);
216         ok(((hr == E_INVALIDARG) && (len == 0)) ||
217             (((hr == S_OK) && !lstrcmpA(buffer, language)  && (len == lstrlenA(language))) ||
218             ((hr == S_OK) && !memcmp(buffer, language, len)) ||
219             ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len)),
220             "=1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
221
222         len = maxlen;
223         hr = pGetAcceptLanguagesA( NULL, &len);
224
225         /* w2k3 and below: E_FAIL and untouched len,
226            since w2k8: S_OK and needed size (excluding 0) */
227         ok( ((hr == S_OK) && (len == exactsize)) ||
228             ((hr == E_FAIL) && (len == maxlen)),
229             "NULL,max #%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
230
231         i++;
232     }
233
234     /* without a value in the registry, a default language is returned */
235     RegDeleteValue(hroot, acceptlanguage);
236
237     len = maxlen;
238     memset(buffer, '#', maxlen);
239     buffer[maxlen] = 0;
240     hr = pGetAcceptLanguagesA( buffer, &len);
241     ok( ((hr == S_OK) && (len == lstrlenA(language))),
242         "max: got 0x%x with %d and %s (expected S_OK with %d and '%s'\n",
243         hr, len, buffer, lstrlenA(language), language);
244
245     len = 2;
246     memset(buffer, '#', maxlen);
247     buffer[maxlen] = 0;
248     hr = pGetAcceptLanguagesA( buffer, &len);
249     ok( (((hr == S_OK) || (hr == E_INVALIDARG)) && !memcmp(buffer, language, len)) ||
250         ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len),
251         "=2: got 0x%x with %d and %s\n", hr, len, buffer);
252
253     len = 1;
254     memset(buffer, '#', maxlen);
255     buffer[maxlen] = 0;
256     hr = pGetAcceptLanguagesA( buffer, &len);
257     /* When the buffer is to small, win7_32 and w2k8_64 and above fail with
258        HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), other versions suceed
259        and return a partial 0 terminated result while other versions
260        fail with E_INVALIDARG and return a partial unterminated result */
261     ok( (((hr == S_OK) || (hr == E_INVALIDARG)) && !memcmp(buffer, language, len)) ||
262         ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len),
263         "=1: got 0x%x with %d and %s\n", hr, len, buffer);
264
265     len = 0;
266     memset(buffer, '#', maxlen);
267     buffer[maxlen] = 0;
268     hr = pGetAcceptLanguagesA( buffer, &len);
269     /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG */
270     ok((hr == E_FAIL) || (hr == E_INVALIDARG),
271         "got 0x%x (expected E_FAIL or E_INVALIDARG)\n", hr);
272
273     memset(buffer, '#', maxlen);
274     buffer[maxlen] = 0;
275     hr = pGetAcceptLanguagesA( buffer, NULL);
276     /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG */
277     ok((hr == E_FAIL) || (hr == E_INVALIDARG),
278         "got 0x%x (expected E_FAIL or E_INVALIDARG)\n", hr);
279
280
281     hr = pGetAcceptLanguagesA( NULL, NULL);
282     /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG */
283     ok((hr == E_FAIL) || (hr == E_INVALIDARG),
284         "got 0x%x (expected E_FAIL or E_INVALIDARG)\n", hr);
285
286 restore_original:
287     if (!res_query) {
288         len = lstrlenA(original);
289         lres = RegSetValueExA(hroot, acceptlanguage, 0, REG_SZ, (const BYTE *) original, len ? len + 1: 0);
290         ok(!lres, "RegSetValueEx(%s) failed: %d\n", original, lres);
291     }
292     else
293     {
294         RegDeleteValue(hroot, acceptlanguage);
295     }
296     RegCloseKey(hroot);
297 }
298
299 static void test_SHSearchMapInt(void)
300 {
301   int keys[8], values[8];
302   int i = 0;
303
304   if (!pSHSearchMapInt)
305     return;
306
307   memset(keys, 0, sizeof(keys));
308   memset(values, 0, sizeof(values));
309   keys[0] = 99; values[0] = 101;
310
311   /* NULL key/value lists crash native, so skip testing them */
312
313   /* 1 element */
314   i = pSHSearchMapInt(keys, values, 1, keys[0]);
315   ok(i == values[0], "Len 1, expected %d, got %d\n", values[0], i);
316
317   /* Key doesn't exist */
318   i = pSHSearchMapInt(keys, values, 1, 100);
319   ok(i == -1, "Len 1 - bad key, expected -1, got %d\n", i);
320
321   /* Len = 0 => not found */
322   i = pSHSearchMapInt(keys, values, 0, keys[0]);
323   ok(i == -1, "Len 1 - passed len 0, expected -1, got %d\n", i);
324
325   /* 2 elements, len = 1 */
326   keys[1] = 98; values[1] = 102;
327   i = pSHSearchMapInt(keys, values, 1, keys[1]);
328   ok(i == -1, "Len 1 - array len 2, expected -1, got %d\n", i);
329
330   /* 2 elements, len = 2 */
331   i = pSHSearchMapInt(keys, values, 2, keys[1]);
332   ok(i == values[1], "Len 2, expected %d, got %d\n", values[1], i);
333
334   /* Searches forward */
335   keys[2] = 99; values[2] = 103;
336   i = pSHSearchMapInt(keys, values, 3, keys[0]);
337   ok(i == values[0], "Len 3, expected %d, got %d\n", values[0], i);
338 }
339
340 static void test_alloc_shared(void)
341 {
342     DWORD procid;
343     HANDLE hmem;
344     int val;
345     int* p;
346     BOOL ret;
347
348     procid=GetCurrentProcessId();
349     hmem=pSHAllocShared(NULL,10,procid);
350     ok(hmem!=NULL,"SHAllocShared(NULL...) failed: %u\n", GetLastError());
351     ret = pSHFreeShared(hmem, procid);
352     ok( ret, "SHFreeShared failed: %u\n", GetLastError());
353
354     val=0x12345678;
355     hmem=pSHAllocShared(&val,4,procid);
356     ok(hmem!=NULL,"SHAllocShared(NULL...) failed: %u\n", GetLastError());
357
358     p=pSHLockShared(hmem,procid);
359     ok(p!=NULL,"SHLockShared failed: %u\n", GetLastError());
360     if (p!=NULL)
361         ok(*p==val,"Wrong value in shared memory: %d instead of %d\n",*p,val);
362     ret = pSHUnlockShared(p);
363     ok( ret, "SHUnlockShared failed: %u\n", GetLastError());
364
365     ret = pSHFreeShared(hmem, procid);
366     ok( ret, "SHFreeShared failed: %u\n", GetLastError());
367 }
368
369 static void test_fdsa(void)
370 {
371     typedef struct
372     {
373         DWORD num_items;       /* Number of elements inserted */
374         void *mem;             /* Ptr to array */
375         DWORD blocks_alloced;  /* Number of elements allocated */
376         BYTE inc;              /* Number of elements to grow by when we need to expand */
377         BYTE block_size;       /* Size in bytes of an element */
378         BYTE flags;            /* Flags */
379     } FDSA_info;
380
381     BOOL (WINAPI *pFDSA_Initialize)(DWORD block_size, DWORD inc, FDSA_info *info, void *mem,
382                                     DWORD init_blocks);
383     BOOL (WINAPI *pFDSA_Destroy)(FDSA_info *info);
384     DWORD (WINAPI *pFDSA_InsertItem)(FDSA_info *info, DWORD where, const void *block);
385     BOOL (WINAPI *pFDSA_DeleteItem)(FDSA_info *info, DWORD where);
386
387     FDSA_info info;
388     int block_size = 10, init_blocks = 4, inc = 2;
389     DWORD ret;
390     char *mem;
391
392     pFDSA_Initialize = (void *)GetProcAddress(hShlwapi, (LPSTR)208);
393     pFDSA_Destroy    = (void *)GetProcAddress(hShlwapi, (LPSTR)209);
394     pFDSA_InsertItem = (void *)GetProcAddress(hShlwapi, (LPSTR)210);
395     pFDSA_DeleteItem = (void *)GetProcAddress(hShlwapi, (LPSTR)211);
396
397     mem = HeapAlloc(GetProcessHeap(), 0, block_size * init_blocks);
398     memset(&info, 0, sizeof(info));
399
400     ok(pFDSA_Initialize(block_size, inc, &info, mem, init_blocks), "FDSA_Initialize rets FALSE\n");
401     ok(info.num_items == 0, "num_items = %d\n", info.num_items);
402     ok(info.mem == mem, "mem = %p\n", info.mem);
403     ok(info.blocks_alloced == init_blocks, "blocks_alloced = %d\n", info.blocks_alloced);
404     ok(info.inc == inc, "inc = %d\n", info.inc);
405     ok(info.block_size == block_size, "block_size = %d\n", info.block_size);
406     ok(info.flags == 0, "flags = %d\n", info.flags);
407
408     ret = pFDSA_InsertItem(&info, 1234, "1234567890");
409     ok(ret == 0, "ret = %d\n", ret);
410     ok(info.num_items == 1, "num_items = %d\n", info.num_items);
411     ok(info.mem == mem, "mem = %p\n", info.mem);
412     ok(info.blocks_alloced == init_blocks, "blocks_alloced = %d\n", info.blocks_alloced);
413     ok(info.inc == inc, "inc = %d\n", info.inc);
414     ok(info.block_size == block_size, "block_size = %d\n", info.block_size);
415     ok(info.flags == 0, "flags = %d\n", info.flags);
416
417     ret = pFDSA_InsertItem(&info, 1234, "abcdefghij");
418     ok(ret == 1, "ret = %d\n", ret);
419
420     ret = pFDSA_InsertItem(&info, 1, "klmnopqrst");
421     ok(ret == 1, "ret = %d\n", ret);
422
423     ret = pFDSA_InsertItem(&info, 0, "uvwxyzABCD");
424     ok(ret == 0, "ret = %d\n", ret);
425     ok(info.mem == mem, "mem = %p\n", info.mem);
426     ok(info.flags == 0, "flags = %d\n", info.flags);
427
428     /* This next InsertItem will cause shlwapi to allocate its own mem buffer */
429     ret = pFDSA_InsertItem(&info, 0, "EFGHIJKLMN");
430     ok(ret == 0, "ret = %d\n", ret);
431     ok(info.mem != mem, "mem = %p\n", info.mem);
432     ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %d\n", info.blocks_alloced);
433     ok(info.flags == 0x1, "flags = %d\n", info.flags);
434
435     ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCD1234567890klmnopqrstabcdefghij", 50), "mem %s\n", (char*)info.mem);
436
437     ok(pFDSA_DeleteItem(&info, 2), "rets FALSE\n");
438     ok(info.mem != mem, "mem = %p\n", info.mem);
439     ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %d\n", info.blocks_alloced);
440     ok(info.flags == 0x1, "flags = %d\n", info.flags);
441
442     ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCDklmnopqrstabcdefghij", 40), "mem %s\n", (char*)info.mem);
443
444     ok(pFDSA_DeleteItem(&info, 3), "rets FALSE\n");
445     ok(info.mem != mem, "mem = %p\n", info.mem);
446     ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %d\n", info.blocks_alloced);
447     ok(info.flags == 0x1, "flags = %d\n", info.flags);
448
449     ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCDklmnopqrst", 30), "mem %s\n", (char*)info.mem);
450
451     ok(!pFDSA_DeleteItem(&info, 4), "does not ret FALSE\n");
452
453     /* As shlwapi has allocated memory internally, Destroy will ret FALSE */
454     ok(!pFDSA_Destroy(&info), "FDSA_Destroy does not ret FALSE\n");
455
456
457     /* When Initialize is called with inc = 0, set it to 1 */
458     ok(pFDSA_Initialize(block_size, 0, &info, mem, init_blocks), "FDSA_Initialize rets FALSE\n");
459     ok(info.inc == 1, "inc = %d\n", info.inc);
460
461     /* This time, because shlwapi hasn't had to allocate memory
462        internally, Destroy rets non-zero */
463     ok(pFDSA_Destroy(&info), "FDSA_Destroy rets FALSE\n");
464
465
466     HeapFree(GetProcessHeap(), 0, mem);
467 }
468
469
470 typedef struct SHELL_USER_SID {
471     SID_IDENTIFIER_AUTHORITY sidAuthority;
472     DWORD                    dwUserGroupID;
473     DWORD                    dwUserID;
474 } SHELL_USER_SID, *PSHELL_USER_SID;
475 typedef struct SHELL_USER_PERMISSION {
476     SHELL_USER_SID susID;
477     DWORD          dwAccessType;
478     BOOL           fInherit;
479     DWORD          dwAccessMask;
480     DWORD          dwInheritMask;
481     DWORD          dwInheritAccessMask;
482 } SHELL_USER_PERMISSION, *PSHELL_USER_PERMISSION;
483 static void test_GetShellSecurityDescriptor(void)
484 {
485     SHELL_USER_PERMISSION supCurrentUserFull = {
486         { {SECURITY_NULL_SID_AUTHORITY}, 0, 0 },
487         ACCESS_ALLOWED_ACE_TYPE, FALSE,
488         GENERIC_ALL, 0, 0 };
489 #define MY_INHERITANCE 0xBE /* invalid value to proof behavior */
490     SHELL_USER_PERMISSION supEveryoneDenied = {
491         { {SECURITY_WORLD_SID_AUTHORITY}, SECURITY_WORLD_RID, 0 },
492         ACCESS_DENIED_ACE_TYPE, TRUE,
493         GENERIC_WRITE, MY_INHERITANCE | 0xDEADBA00, GENERIC_READ };
494     PSHELL_USER_PERMISSION rgsup[2] = {
495         &supCurrentUserFull, &supEveryoneDenied,
496     };
497     SECURITY_DESCRIPTOR* psd;
498     SECURITY_DESCRIPTOR* (WINAPI*pGetShellSecurityDescriptor)(PSHELL_USER_PERMISSION*,int);
499
500     pGetShellSecurityDescriptor=(void*)GetProcAddress(hShlwapi,(char*)475);
501
502     if(!pGetShellSecurityDescriptor)
503     {
504         win_skip("GetShellSecurityDescriptor not available\n");
505         return;
506     }
507
508     psd = pGetShellSecurityDescriptor(NULL, 2);
509     ok(psd==NULL ||
510        broken(psd==INVALID_HANDLE_VALUE), /* IE5 */
511        "GetShellSecurityDescriptor should fail\n");
512     psd = pGetShellSecurityDescriptor(rgsup, 0);
513     ok(psd==NULL, "GetShellSecurityDescriptor should fail\n");
514
515     SetLastError(0xdeadbeef);
516     psd = pGetShellSecurityDescriptor(rgsup, 2);
517     if (psd == NULL && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
518     {
519         /* The previous calls to GetShellSecurityDescriptor don't set the last error */
520         win_skip("GetShellSecurityDescriptor is not implemented\n");
521         return;
522     }
523     if (psd==INVALID_HANDLE_VALUE)
524     {
525         win_skip("GetShellSecurityDescriptor is broken on IE5\n");
526         return;
527     }
528     ok(psd!=NULL, "GetShellSecurityDescriptor failed\n");
529     if (psd!=NULL)
530     {
531         BOOL bHasDacl = FALSE, bDefaulted;
532         PACL pAcl;
533         DWORD dwRev;
534         SECURITY_DESCRIPTOR_CONTROL control;
535
536         ok(IsValidSecurityDescriptor(psd), "returned value is not valid SD\n");
537
538         ok(GetSecurityDescriptorControl(psd, &control, &dwRev),
539                 "GetSecurityDescriptorControl failed with error %u\n", GetLastError());
540         ok(0 == (control & SE_SELF_RELATIVE), "SD should be absolute\n");
541
542         ok(GetSecurityDescriptorDacl(psd, &bHasDacl, &pAcl, &bDefaulted), 
543             "GetSecurityDescriptorDacl failed with error %u\n", GetLastError());
544
545         ok(bHasDacl, "SD has no DACL\n");
546         if (bHasDacl)
547         {
548             ok(!bDefaulted, "DACL should not be defaulted\n");
549
550             ok(pAcl != NULL, "NULL DACL!\n");
551             if (pAcl != NULL)
552             {
553                 ACL_SIZE_INFORMATION asiSize;
554
555                 ok(IsValidAcl(pAcl), "DACL is not valid\n");
556
557                 ok(GetAclInformation(pAcl, &asiSize, sizeof(asiSize), AclSizeInformation),
558                         "GetAclInformation failed with error %u\n", GetLastError());
559
560                 ok(asiSize.AceCount == 3, "Incorrect number of ACEs: %d entries\n", asiSize.AceCount);
561                 if (asiSize.AceCount == 3)
562                 {
563                     ACCESS_ALLOWED_ACE *paaa; /* will use for DENIED too */
564
565                     ok(GetAce(pAcl, 0, (LPVOID*)&paaa), "GetAce failed with error %u\n", GetLastError());
566                     ok(paaa->Header.AceType == ACCESS_ALLOWED_ACE_TYPE, 
567                             "Invalid ACE type %d\n", paaa->Header.AceType); 
568                     ok(paaa->Header.AceFlags == 0, "Invalid ACE flags %x\n", paaa->Header.AceFlags);
569                     ok(paaa->Mask == GENERIC_ALL, "Invalid ACE mask %x\n", paaa->Mask);
570
571                     ok(GetAce(pAcl, 1, (LPVOID*)&paaa), "GetAce failed with error %u\n", GetLastError());
572                     ok(paaa->Header.AceType == ACCESS_DENIED_ACE_TYPE, 
573                             "Invalid ACE type %d\n", paaa->Header.AceType); 
574                     /* first one of two ACEs generated from inheritable entry - without inheritance */
575                     ok(paaa->Header.AceFlags == 0, "Invalid ACE flags %x\n", paaa->Header.AceFlags);
576                     ok(paaa->Mask == GENERIC_WRITE, "Invalid ACE mask %x\n", paaa->Mask);
577
578                     ok(GetAce(pAcl, 2, (LPVOID*)&paaa), "GetAce failed with error %u\n", GetLastError());
579                     ok(paaa->Header.AceType == ACCESS_DENIED_ACE_TYPE, 
580                             "Invalid ACE type %d\n", paaa->Header.AceType); 
581                     /* second ACE - with inheritance */
582                     ok(paaa->Header.AceFlags == MY_INHERITANCE,
583                             "Invalid ACE flags %x\n", paaa->Header.AceFlags);
584                     ok(paaa->Mask == GENERIC_READ, "Invalid ACE mask %x\n", paaa->Mask);
585                 }
586             }
587         }
588
589         LocalFree(psd);
590     }
591 }
592
593 static void test_SHPackDispParams(void)
594 {
595     DISPPARAMS params;
596     VARIANT vars[10];
597     HRESULT hres;
598
599     if(!pSHPackDispParams)
600         win_skip("SHPackSidpParams not available\n");
601
602     memset(&params, 0xc0, sizeof(params));
603     memset(vars, 0xc0, sizeof(vars));
604     hres = pSHPackDispParams(&params, vars, 1, VT_I4, 0xdeadbeef);
605     ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres);
606     ok(params.cArgs == 1, "params.cArgs = %d\n", params.cArgs);
607     ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
608     ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
609     ok(params.rgvarg == vars, "params.rgvarg = %p\n", params.rgvarg);
610     ok(V_VT(vars) == VT_I4, "V_VT(var) = %d\n", V_VT(vars));
611     ok(V_I4(vars) == 0xdeadbeef, "failed %x\n", V_I4(vars));
612
613     memset(&params, 0xc0, sizeof(params));
614     hres = pSHPackDispParams(&params, NULL, 0, 0);
615     ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres);
616     ok(params.cArgs == 0, "params.cArgs = %d\n", params.cArgs);
617     ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
618     ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
619     ok(params.rgvarg == NULL, "params.rgvarg = %p\n", params.rgvarg);
620
621     memset(vars, 0xc0, sizeof(vars));
622     memset(&params, 0xc0, sizeof(params));
623     hres = pSHPackDispParams(&params, vars, 4, VT_BSTR, (void*)0xdeadbeef, VT_EMPTY, 10,
624             VT_I4, 100, VT_DISPATCH, (void*)0xdeadbeef);
625     ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres);
626     ok(params.cArgs == 4, "params.cArgs = %d\n", params.cArgs);
627     ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
628     ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
629     ok(params.rgvarg == vars, "params.rgvarg = %p\n", params.rgvarg);
630     ok(V_VT(vars) == VT_DISPATCH, "V_VT(vars[0]) = %x\n", V_VT(vars));
631     ok(V_I4(vars) == 0xdeadbeef, "V_I4(vars[0]) = %x\n", V_I4(vars));
632     ok(V_VT(vars+1) == VT_I4, "V_VT(vars[1]) = %d\n", V_VT(vars+1));
633     ok(V_I4(vars+1) == 100, "V_I4(vars[1]) = %x\n", V_I4(vars+1));
634     ok(V_VT(vars+2) == VT_I4, "V_VT(vars[2]) = %d\n", V_VT(vars+2));
635     ok(V_I4(vars+2) == 10, "V_I4(vars[2]) = %x\n", V_I4(vars+2));
636     ok(V_VT(vars+3) == VT_BSTR, "V_VT(vars[3]) = %d\n", V_VT(vars+3));
637     ok(V_BSTR(vars+3) == (void*)0xdeadbeef, "V_BSTR(vars[3]) = %p\n", V_BSTR(vars+3));
638 }
639
640 typedef struct _disp
641 {
642     const IDispatchVtbl *vtbl;
643     LONG   refCount;
644 } Disp;
645
646 typedef struct _contain
647 {
648     const IConnectionPointContainerVtbl *vtbl;
649     LONG   refCount;
650
651     UINT  ptCount;
652     IConnectionPoint **pt;
653 } Contain;
654
655 typedef struct _cntptn
656 {
657     const IConnectionPointVtbl *vtbl;
658     LONG refCount;
659
660     Contain *container;
661     GUID  id;
662     UINT  sinkCount;
663     IUnknown **sink;
664 } ConPt;
665
666 typedef struct _enum
667 {
668     const IEnumConnectionsVtbl *vtbl;
669     LONG   refCount;
670
671     UINT idx;
672     ConPt *pt;
673 } EnumCon;
674
675 typedef struct _enumpt
676 {
677     const IEnumConnectionPointsVtbl *vtbl;
678     LONG   refCount;
679
680     int idx;
681     Contain *container;
682 } EnumPt;
683
684
685 static HRESULT WINAPI Disp_QueryInterface(
686         IDispatch* This,
687         REFIID riid,
688         void **ppvObject)
689 {
690     *ppvObject = NULL;
691
692     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDispatch))
693     {
694         *ppvObject = This;
695     }
696
697     if (*ppvObject)
698     {
699         IUnknown_AddRef(This);
700         return S_OK;
701     }
702
703     trace("no interface\n");
704     return E_NOINTERFACE;
705 }
706
707 static ULONG WINAPI Disp_AddRef(IDispatch* This)
708 {
709     Disp *iface = (Disp*)This;
710     return InterlockedIncrement(&iface->refCount);
711 }
712
713 static ULONG WINAPI Disp_Release(IDispatch* This)
714 {
715     Disp *iface = (Disp*)This;
716     ULONG ret;
717
718     ret = InterlockedDecrement(&iface->refCount);
719     if (ret == 0)
720         HeapFree(GetProcessHeap(),0,This);
721     return ret;
722 }
723
724 static HRESULT WINAPI Disp_GetTypeInfoCount(
725         IDispatch* This,
726         UINT *pctinfo)
727 {
728     return ERROR_SUCCESS;
729 }
730
731 static HRESULT WINAPI Disp_GetTypeInfo(
732         IDispatch* This,
733         UINT iTInfo,
734         LCID lcid,
735         ITypeInfo **ppTInfo)
736 {
737     return ERROR_SUCCESS;
738 }
739
740 static HRESULT WINAPI Disp_GetIDsOfNames(
741         IDispatch* This,
742         REFIID riid,
743         LPOLESTR *rgszNames,
744         UINT cNames,
745         LCID lcid,
746         DISPID *rgDispId)
747 {
748     return ERROR_SUCCESS;
749 }
750
751 static HRESULT WINAPI Disp_Invoke(
752         IDispatch* This,
753         DISPID dispIdMember,
754         REFIID riid,
755         LCID lcid,
756         WORD wFlags,
757         DISPPARAMS *pDispParams,
758         VARIANT *pVarResult,
759         EXCEPINFO *pExcepInfo,
760         UINT *puArgErr)
761 {
762     trace("%p %x %p %x %x %p %p %p %p\n",This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
763
764     ok(dispIdMember == 0xa0 || dispIdMember == 0xa1, "Unknown dispIdMember\n");
765     ok(pDispParams != NULL, "Invoked with NULL pDispParams\n");
766     ok(wFlags == DISPATCH_METHOD, "Wrong flags %x\n",wFlags);
767     ok(lcid == 0,"Wrong lcid %x\n",lcid);
768     if (dispIdMember == 0xa0)
769     {
770         ok(pDispParams->cArgs == 0, "params.cArgs = %d\n", pDispParams->cArgs);
771         ok(pDispParams->cNamedArgs == 0, "params.cNamedArgs = %d\n", pDispParams->cArgs);
772         ok(pDispParams->rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", pDispParams->rgdispidNamedArgs);
773         ok(pDispParams->rgvarg == NULL, "params.rgvarg = %p\n", pDispParams->rgvarg);
774     }
775     else if (dispIdMember == 0xa1)
776     {
777         ok(pDispParams->cArgs == 2, "params.cArgs = %d\n", pDispParams->cArgs);
778         ok(pDispParams->cNamedArgs == 0, "params.cNamedArgs = %d\n", pDispParams->cArgs);
779         ok(pDispParams->rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", pDispParams->rgdispidNamedArgs);
780         ok(V_VT(pDispParams->rgvarg) == VT_BSTR, "V_VT(var) = %d\n", V_VT(pDispParams->rgvarg));
781         ok(V_I4(pDispParams->rgvarg) == 0xdeadcafe , "failed %p\n", V_BSTR(pDispParams->rgvarg));
782         ok(V_VT(pDispParams->rgvarg+1) == VT_I4, "V_VT(var) = %d\n", V_VT(pDispParams->rgvarg+1));
783         ok(V_I4(pDispParams->rgvarg+1) == 0xdeadbeef, "failed %x\n", V_I4(pDispParams->rgvarg+1));
784     }
785
786     return ERROR_SUCCESS;
787 }
788
789 static const IDispatchVtbl disp_vtbl = {
790     Disp_QueryInterface,
791     Disp_AddRef,
792     Disp_Release,
793
794     Disp_GetTypeInfoCount,
795     Disp_GetTypeInfo,
796     Disp_GetIDsOfNames,
797     Disp_Invoke
798 };
799
800 static HRESULT WINAPI Enum_QueryInterface(
801         IEnumConnections* This,
802         REFIID riid,
803         void **ppvObject)
804 {
805     *ppvObject = NULL;
806
807     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumConnections))
808     {
809         *ppvObject = This;
810     }
811
812     if (*ppvObject)
813     {
814         IUnknown_AddRef(This);
815         return S_OK;
816     }
817
818     trace("no interface\n");
819     return E_NOINTERFACE;
820 }
821
822 static ULONG WINAPI Enum_AddRef(IEnumConnections* This)
823 {
824     EnumCon *iface = (EnumCon*)This;
825     return InterlockedIncrement(&iface->refCount);
826 }
827
828 static ULONG WINAPI Enum_Release(IEnumConnections* This)
829 {
830     EnumCon *iface = (EnumCon*)This;
831     ULONG ret;
832
833     ret = InterlockedDecrement(&iface->refCount);
834     if (ret == 0)
835         HeapFree(GetProcessHeap(),0,This);
836     return ret;
837 }
838
839 static HRESULT WINAPI Enum_Next(
840         IEnumConnections* This,
841         ULONG cConnections,
842         LPCONNECTDATA rgcd,
843         ULONG *pcFetched)
844 {
845     EnumCon *iface = (EnumCon*)This;
846
847     if (cConnections > 0 && iface->idx < iface->pt->sinkCount)
848     {
849         rgcd->pUnk = iface->pt->sink[iface->idx];
850         IUnknown_AddRef(iface->pt->sink[iface->idx]);
851         rgcd->dwCookie=0xff;
852         if (pcFetched)
853             *pcFetched = 1;
854         iface->idx++;
855         return S_OK;
856     }
857
858     return E_FAIL;
859 }
860
861 static HRESULT WINAPI Enum_Skip(
862         IEnumConnections* This,
863         ULONG cConnections)
864 {
865     return E_FAIL;
866 }
867
868 static HRESULT WINAPI Enum_Reset(
869         IEnumConnections* This)
870 {
871     return E_FAIL;
872 }
873
874 static HRESULT WINAPI Enum_Clone(
875         IEnumConnections* This,
876         IEnumConnections **ppEnum)
877 {
878     return E_FAIL;
879 }
880
881 static const IEnumConnectionsVtbl enum_vtbl = {
882
883     Enum_QueryInterface,
884     Enum_AddRef,
885     Enum_Release,
886     Enum_Next,
887     Enum_Skip,
888     Enum_Reset,
889     Enum_Clone
890 };
891
892 static HRESULT WINAPI ConPt_QueryInterface(
893         IConnectionPoint* This,
894         REFIID riid,
895         void **ppvObject)
896 {
897     *ppvObject = NULL;
898
899     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IConnectionPoint))
900     {
901         *ppvObject = This;
902     }
903
904     if (*ppvObject)
905     {
906         IUnknown_AddRef(This);
907         return S_OK;
908     }
909
910     trace("no interface\n");
911     return E_NOINTERFACE;
912 }
913
914 static ULONG WINAPI ConPt_AddRef(
915         IConnectionPoint* This)
916 {
917     ConPt *iface = (ConPt*)This;
918     return InterlockedIncrement(&iface->refCount);
919 }
920
921 static ULONG WINAPI ConPt_Release(
922         IConnectionPoint* This)
923 {
924     ConPt *iface = (ConPt*)This;
925     ULONG ret;
926
927     ret = InterlockedDecrement(&iface->refCount);
928     if (ret == 0)
929     {
930         if (iface->sinkCount > 0)
931         {
932             int i;
933             for (i = 0; i < iface->sinkCount; i++)
934             {
935                 if (iface->sink[i])
936                     IUnknown_Release(iface->sink[i]);
937             }
938             HeapFree(GetProcessHeap(),0,iface->sink);
939         }
940         HeapFree(GetProcessHeap(),0,This);
941     }
942     return ret;
943 }
944
945 static HRESULT WINAPI ConPt_GetConnectionInterface(
946         IConnectionPoint* This,
947         IID *pIID)
948 {
949     static int i = 0;
950     ConPt *iface = (ConPt*)This;
951     if (i==0)
952     {
953         i++;
954         return E_FAIL;
955     }
956     else
957         memcpy(pIID,&iface->id,sizeof(GUID));
958     return S_OK;
959 }
960
961 static HRESULT WINAPI ConPt_GetConnectionPointContainer(
962         IConnectionPoint* This,
963         IConnectionPointContainer **ppCPC)
964 {
965     ConPt *iface = (ConPt*)This;
966
967     *ppCPC = (IConnectionPointContainer*)iface->container;
968     return S_OK;
969 }
970
971 static HRESULT WINAPI ConPt_Advise(
972         IConnectionPoint* This,
973         IUnknown *pUnkSink,
974         DWORD *pdwCookie)
975 {
976     ConPt *iface = (ConPt*)This;
977
978     if (iface->sinkCount == 0)
979         iface->sink = HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown*));
980     else
981         iface->sink = HeapReAlloc(GetProcessHeap(),0,iface->sink,sizeof(IUnknown*)*(iface->sinkCount+1));
982     iface->sink[iface->sinkCount] = pUnkSink;
983     IUnknown_AddRef(pUnkSink);
984     iface->sinkCount++;
985     *pdwCookie = iface->sinkCount;
986     return S_OK;
987 }
988
989 static HRESULT WINAPI ConPt_Unadvise(
990         IConnectionPoint* This,
991         DWORD dwCookie)
992 {
993     ConPt *iface = (ConPt*)This;
994
995     if (dwCookie > iface->sinkCount)
996         return E_FAIL;
997     else
998     {
999         IUnknown_Release(iface->sink[dwCookie-1]);
1000         iface->sink[dwCookie-1] = NULL;
1001     }
1002     return S_OK;
1003 }
1004
1005 static HRESULT WINAPI ConPt_EnumConnections(
1006         IConnectionPoint* This,
1007         IEnumConnections **ppEnum)
1008 {
1009     EnumCon *ec;
1010
1011     ec = HeapAlloc(GetProcessHeap(),0,sizeof(EnumCon));
1012     ec->vtbl = &enum_vtbl;
1013     ec->refCount = 1;
1014     ec->pt = (ConPt*)This;
1015     ec->idx = 0;
1016     *ppEnum = (IEnumConnections*)ec;
1017
1018     return S_OK;
1019 }
1020
1021 static const IConnectionPointVtbl point_vtbl = {
1022     ConPt_QueryInterface,
1023     ConPt_AddRef,
1024     ConPt_Release,
1025
1026     ConPt_GetConnectionInterface,
1027     ConPt_GetConnectionPointContainer,
1028     ConPt_Advise,
1029     ConPt_Unadvise,
1030     ConPt_EnumConnections
1031 };
1032
1033 static HRESULT WINAPI EnumPt_QueryInterface(
1034         IEnumConnectionPoints* This,
1035         REFIID riid,
1036         void **ppvObject)
1037 {
1038     *ppvObject = NULL;
1039
1040     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumConnectionPoints))
1041     {
1042         *ppvObject = This;
1043     }
1044
1045     if (*ppvObject)
1046     {
1047         IUnknown_AddRef(This);
1048         return S_OK;
1049     }
1050
1051     trace("no interface\n");
1052     return E_NOINTERFACE;
1053 }
1054
1055 static ULONG WINAPI EnumPt_AddRef(IEnumConnectionPoints* This)
1056 {
1057     EnumPt *iface = (EnumPt*)This;
1058     return InterlockedIncrement(&iface->refCount);
1059 }
1060
1061 static ULONG WINAPI EnumPt_Release(IEnumConnectionPoints* This)
1062 {
1063     EnumPt *iface = (EnumPt*)This;
1064     ULONG ret;
1065
1066     ret = InterlockedDecrement(&iface->refCount);
1067     if (ret == 0)
1068         HeapFree(GetProcessHeap(),0,This);
1069     return ret;
1070 }
1071
1072 static HRESULT WINAPI EnumPt_Next(
1073         IEnumConnectionPoints* This,
1074         ULONG cConnections,
1075         IConnectionPoint **rgcd,
1076         ULONG *pcFetched)
1077 {
1078     EnumPt *iface = (EnumPt*)This;
1079
1080     if (cConnections > 0 && iface->idx < iface->container->ptCount)
1081     {
1082         *rgcd = iface->container->pt[iface->idx];
1083         IUnknown_AddRef(iface->container->pt[iface->idx]);
1084         if (pcFetched)
1085             *pcFetched = 1;
1086         iface->idx++;
1087         return S_OK;
1088     }
1089
1090     return E_FAIL;
1091 }
1092
1093 static HRESULT WINAPI EnumPt_Skip(
1094         IEnumConnectionPoints* This,
1095         ULONG cConnections)
1096 {
1097     return E_FAIL;
1098 }
1099
1100 static HRESULT WINAPI EnumPt_Reset(
1101         IEnumConnectionPoints* This)
1102 {
1103     return E_FAIL;
1104 }
1105
1106 static HRESULT WINAPI EnumPt_Clone(
1107         IEnumConnectionPoints* This,
1108         IEnumConnectionPoints **ppEnumPt)
1109 {
1110     return E_FAIL;
1111 }
1112
1113 static const IEnumConnectionPointsVtbl enumpt_vtbl = {
1114
1115     EnumPt_QueryInterface,
1116     EnumPt_AddRef,
1117     EnumPt_Release,
1118     EnumPt_Next,
1119     EnumPt_Skip,
1120     EnumPt_Reset,
1121     EnumPt_Clone
1122 };
1123
1124 static HRESULT WINAPI Contain_QueryInterface(
1125         IConnectionPointContainer* This,
1126         REFIID riid,
1127         void **ppvObject)
1128 {
1129     *ppvObject = NULL;
1130
1131     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IConnectionPointContainer))
1132     {
1133         *ppvObject = This;
1134     }
1135
1136     if (*ppvObject)
1137     {
1138         IUnknown_AddRef(This);
1139         return S_OK;
1140     }
1141
1142     trace("no interface\n");
1143     return E_NOINTERFACE;
1144 }
1145
1146 static ULONG WINAPI Contain_AddRef(
1147         IConnectionPointContainer* This)
1148 {
1149     Contain *iface = (Contain*)This;
1150     return InterlockedIncrement(&iface->refCount);
1151 }
1152
1153 static ULONG WINAPI Contain_Release(
1154         IConnectionPointContainer* This)
1155 {
1156     Contain *iface = (Contain*)This;
1157     ULONG ret;
1158
1159     ret = InterlockedDecrement(&iface->refCount);
1160     if (ret == 0)
1161     {
1162         if (iface->ptCount > 0)
1163         {
1164             int i;
1165             for (i = 0; i < iface->ptCount; i++)
1166                 IUnknown_Release(iface->pt[i]);
1167             HeapFree(GetProcessHeap(),0,iface->pt);
1168         }
1169         HeapFree(GetProcessHeap(),0,This);
1170     }
1171     return ret;
1172 }
1173
1174 static HRESULT WINAPI Contain_EnumConnectionPoints(
1175         IConnectionPointContainer* This,
1176         IEnumConnectionPoints **ppEnum)
1177 {
1178     EnumPt *ec;
1179
1180     ec = HeapAlloc(GetProcessHeap(),0,sizeof(EnumPt));
1181     ec->vtbl = &enumpt_vtbl;
1182     ec->refCount = 1;
1183     ec->idx= 0;
1184     ec->container = (Contain*)This;
1185     *ppEnum = (IEnumConnectionPoints*)ec;
1186
1187     return S_OK;
1188 }
1189
1190 static HRESULT WINAPI Contain_FindConnectionPoint(
1191         IConnectionPointContainer* This,
1192         REFIID riid,
1193         IConnectionPoint **ppCP)
1194 {
1195     Contain *iface = (Contain*)This;
1196     ConPt *pt;
1197
1198     if (!IsEqualIID(riid, &IID_NULL) || iface->ptCount ==0)
1199     {
1200         pt = HeapAlloc(GetProcessHeap(),0,sizeof(ConPt));
1201         pt->vtbl = &point_vtbl;
1202         pt->refCount = 1;
1203         pt->sinkCount = 0;
1204         pt->sink = NULL;
1205         pt->container = iface;
1206         pt->id = IID_IDispatch;
1207
1208         if (iface->ptCount == 0)
1209             iface->pt =HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown*));
1210         else
1211             iface->pt = HeapReAlloc(GetProcessHeap(),0,iface->pt,sizeof(IUnknown*)*(iface->ptCount+1));
1212         iface->pt[iface->ptCount] = (IConnectionPoint*)pt;
1213         iface->ptCount++;
1214
1215         *ppCP = (IConnectionPoint*)pt;
1216     }
1217     else
1218     {
1219         *ppCP = iface->pt[0];
1220         IUnknown_AddRef((IUnknown*)*ppCP);
1221     }
1222
1223     return S_OK;
1224 }
1225
1226 static const IConnectionPointContainerVtbl contain_vtbl = {
1227     Contain_QueryInterface,
1228     Contain_AddRef,
1229     Contain_Release,
1230
1231     Contain_EnumConnectionPoints,
1232     Contain_FindConnectionPoint
1233 };
1234
1235 static void test_IConnectionPoint(void)
1236 {
1237     HRESULT rc;
1238     ULONG ref;
1239     IConnectionPoint *point;
1240     Contain *container;
1241     Disp *dispatch;
1242     DWORD cookie = 0xffffffff;
1243     DISPPARAMS params;
1244     VARIANT vars[10];
1245
1246     if (!pIConnectionPoint_SimpleInvoke || !pConnectToConnectionPoint)
1247     {
1248         win_skip("IConnectionPoint Apis not present\n");
1249         return;
1250     }
1251
1252     container = HeapAlloc(GetProcessHeap(),0,sizeof(Contain));
1253     container->vtbl = &contain_vtbl;
1254     container->refCount = 1;
1255     container->ptCount = 0;
1256     container->pt = NULL;
1257
1258     dispatch = HeapAlloc(GetProcessHeap(),0,sizeof(Disp));
1259     dispatch->vtbl = &disp_vtbl;
1260     dispatch->refCount = 1;
1261
1262     rc = pConnectToConnectionPoint((IUnknown*)dispatch, &IID_NULL, TRUE, (IUnknown*)container, &cookie, &point);
1263     ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1264     ok(point != NULL, "returned ConnectionPoint is NULL\n");
1265     ok(cookie != 0xffffffff, "invalid cookie returned\n");
1266
1267     rc = pIConnectionPoint_SimpleInvoke(point,0xa0,NULL);
1268     ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1269
1270     if (pSHPackDispParams)
1271     {
1272         memset(&params, 0xc0, sizeof(params));
1273         memset(vars, 0xc0, sizeof(vars));
1274         rc = pSHPackDispParams(&params, vars, 2, VT_I4, 0xdeadbeef, VT_BSTR, 0xdeadcafe);
1275         ok(rc == S_OK, "SHPackDispParams failed: %08x\n", rc);
1276
1277         rc = pIConnectionPoint_SimpleInvoke(point,0xa1,&params);
1278         ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1279     }
1280     else
1281         win_skip("pSHPackDispParams not present\n");
1282
1283     rc = pConnectToConnectionPoint(NULL, &IID_NULL, FALSE, (IUnknown*)container, &cookie, NULL);
1284     ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1285
1286 /* MSDN says this should be required but it crashs on XP
1287     IUnknown_Release(point);
1288 */
1289     ref = IUnknown_Release((IUnknown*)container);
1290     ok(ref == 0, "leftover IConnectionPointContainer reference %i\n",ref);
1291     ref = IUnknown_Release((IUnknown*)dispatch);
1292     ok(ref == 0, "leftover IDispatch reference %i\n",ref);
1293 }
1294
1295 typedef struct _propbag
1296 {
1297     const IPropertyBagVtbl *vtbl;
1298     LONG   refCount;
1299
1300 } PropBag;
1301
1302
1303 static HRESULT WINAPI Prop_QueryInterface(
1304         IPropertyBag* This,
1305         REFIID riid,
1306         void **ppvObject)
1307 {
1308     *ppvObject = NULL;
1309
1310     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPropertyBag))
1311     {
1312         *ppvObject = This;
1313     }
1314
1315     if (*ppvObject)
1316     {
1317         IUnknown_AddRef(This);
1318         return S_OK;
1319     }
1320
1321     trace("no interface\n");
1322     return E_NOINTERFACE;
1323 }
1324
1325 static ULONG WINAPI Prop_AddRef(
1326         IPropertyBag* This)
1327 {
1328     PropBag *iface = (PropBag*)This;
1329     return InterlockedIncrement(&iface->refCount);
1330 }
1331
1332 static ULONG WINAPI Prop_Release(
1333         IPropertyBag* This)
1334 {
1335     PropBag *iface = (PropBag*)This;
1336     ULONG ret;
1337
1338     ret = InterlockedDecrement(&iface->refCount);
1339     if (ret == 0)
1340         HeapFree(GetProcessHeap(),0,This);
1341     return ret;
1342 }
1343
1344 static HRESULT WINAPI Prop_Read(
1345         IPropertyBag* This,
1346         LPCOLESTR pszPropName,
1347         VARIANT *pVar,
1348         IErrorLog *pErrorLog)
1349 {
1350     V_VT(pVar) = VT_BLOB|VT_BYREF;
1351     V_BYREF(pVar) = (LPVOID)0xdeadcafe;
1352     return S_OK;
1353 }
1354
1355 static HRESULT WINAPI Prop_Write(
1356         IPropertyBag* This,
1357         LPCOLESTR pszPropName,
1358         VARIANT *pVar)
1359 {
1360     return S_OK;
1361 }
1362
1363
1364 static const IPropertyBagVtbl prop_vtbl = {
1365     Prop_QueryInterface,
1366     Prop_AddRef,
1367     Prop_Release,
1368
1369     Prop_Read,
1370     Prop_Write
1371 };
1372
1373 static void test_SHPropertyBag_ReadLONG(void)
1374 {
1375     PropBag *pb;
1376     HRESULT rc;
1377     LONG out;
1378     static const WCHAR szName1[] = {'n','a','m','e','1',0};
1379
1380     if (!pSHPropertyBag_ReadLONG)
1381     {
1382         win_skip("SHPropertyBag_ReadLONG not present\n");
1383         return;
1384     }
1385
1386     pb = HeapAlloc(GetProcessHeap(),0,sizeof(PropBag));
1387     pb->refCount = 1;
1388     pb->vtbl = &prop_vtbl;
1389
1390     out = 0xfeedface;
1391     rc = pSHPropertyBag_ReadLONG(NULL, szName1, &out);
1392     ok(rc == E_INVALIDARG || broken(rc == 0), "incorrect return %x\n",rc);
1393     ok(out == 0xfeedface, "value should not have changed\n");
1394     rc = pSHPropertyBag_ReadLONG((IPropertyBag*)pb, NULL, &out);
1395     ok(rc == E_INVALIDARG || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
1396     ok(out == 0xfeedface, "value should not have changed\n");
1397     rc = pSHPropertyBag_ReadLONG((IPropertyBag*)pb, szName1, NULL);
1398     ok(rc == E_INVALIDARG || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
1399     ok(out == 0xfeedface, "value should not have changed\n");
1400     rc = pSHPropertyBag_ReadLONG((IPropertyBag*)pb, szName1, &out);
1401     ok(rc == DISP_E_BADVARTYPE || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
1402     ok(out == 0xfeedface  || broken(out == 0xfeedfa00), "value should not have changed %x\n",out);
1403     IUnknown_Release((IUnknown*)pb);
1404 }
1405
1406
1407
1408 static void test_SHSetWindowBits(void)
1409 {
1410     HWND hwnd;
1411     DWORD style, styleold;
1412     WNDCLASSA clsA;
1413
1414     if(!pSHSetWindowBits)
1415     {
1416         win_skip("SHSetWindowBits is not available\n");
1417         return;
1418     }
1419
1420     clsA.style = 0;
1421     clsA.lpfnWndProc = DefWindowProcA;
1422     clsA.cbClsExtra = 0;
1423     clsA.cbWndExtra = 0;
1424     clsA.hInstance = GetModuleHandleA(NULL);
1425     clsA.hIcon = 0;
1426     clsA.hCursor = LoadCursorA(0, IDC_ARROW);
1427     clsA.hbrBackground = NULL;
1428     clsA.lpszMenuName = NULL;
1429     clsA.lpszClassName = "Shlwapi test class";
1430     RegisterClassA(&clsA);
1431
1432     hwnd = CreateWindowA("Shlwapi test class", "Test", WS_VISIBLE, 0, 0, 100, 100,
1433                           NULL, NULL, GetModuleHandle(NULL), 0);
1434     ok(IsWindow(hwnd), "failed to create window\n");
1435
1436     /* null window */
1437     SetLastError(0xdeadbeef);
1438     style = pSHSetWindowBits(NULL, GWL_STYLE, 0, 0);
1439     ok(style == 0, "expected 0 retval, got %d\n", style);
1440     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
1441         broken(GetLastError() == 0xdeadbeef), /* Win9x/WinMe */
1442         "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
1443
1444     /* zero mask, zero flags */
1445     styleold = GetWindowLongA(hwnd, GWL_STYLE);
1446     style = pSHSetWindowBits(hwnd, GWL_STYLE, 0, 0);
1447     ok(styleold == style, "expected old style\n");
1448     ok(styleold == GetWindowLongA(hwnd, GWL_STYLE), "expected to keep old style\n");
1449
1450     /* test mask */
1451     styleold = GetWindowLongA(hwnd, GWL_STYLE);
1452     ok(styleold & WS_VISIBLE, "expected WS_VISIBLE\n");
1453     style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1454
1455     ok(style == styleold, "expected previous style, got %x\n", style);
1456     ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1457
1458     /* test mask, unset style bit used */
1459     styleold = GetWindowLongA(hwnd, GWL_STYLE);
1460     style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1461     ok(style == styleold, "expected previous style, got %x\n", style);
1462     ok(styleold == GetWindowLongA(hwnd, GWL_STYLE), "expected to keep old style\n");
1463
1464     /* set back with flags */
1465     styleold = GetWindowLongA(hwnd, GWL_STYLE);
1466     style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, WS_VISIBLE);
1467     ok(style == styleold, "expected previous style, got %x\n", style);
1468     ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "expected updated style\n");
1469
1470     /* reset and try to set without a mask */
1471     pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1472     ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1473     styleold = GetWindowLongA(hwnd, GWL_STYLE);
1474     style = pSHSetWindowBits(hwnd, GWL_STYLE, 0, WS_VISIBLE);
1475     ok(style == styleold, "expected previous style, got %x\n", style);
1476     ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1477
1478     DestroyWindow(hwnd);
1479
1480     UnregisterClassA("Shlwapi test class", GetModuleHandleA(NULL));
1481 }
1482
1483 static void test_SHFormatDateTimeA(void)
1484 {
1485     FILETIME UNALIGNED filetime;
1486     CHAR buff[100], buff2[100], buff3[100];
1487     SYSTEMTIME st;
1488     DWORD flags;
1489     INT ret;
1490
1491     if(!pSHFormatDateTimeA)
1492     {
1493         win_skip("pSHFormatDateTimeA isn't available\n");
1494         return;
1495     }
1496
1497 if (0)
1498 {
1499     /* crashes on native */
1500     ret = pSHFormatDateTimeA(NULL, NULL, NULL, 0);
1501 }
1502
1503     GetLocalTime(&st);
1504     SystemTimeToFileTime(&st, &filetime);
1505     /* SHFormatDateTime expects input as utc */
1506     LocalFileTimeToFileTime(&filetime, &filetime);
1507
1508     /* no way to get required buffer length here */
1509     SetLastError(0xdeadbeef);
1510     ret = pSHFormatDateTimeA(&filetime, NULL, NULL, 0);
1511     ok(ret == 0, "got %d\n", ret);
1512     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1513
1514     SetLastError(0xdeadbeef);
1515     buff[0] = 'a'; buff[1] = 0;
1516     ret = pSHFormatDateTimeA(&filetime, NULL, buff, 0);
1517     ok(ret == 0, "got %d\n", ret);
1518     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1519     ok(buff[0] == 'a', "expected same string, got %s\n", buff);
1520
1521     /* flags needs to have FDTF_NOAUTOREADINGORDER for these tests to succeed on Vista+ */
1522
1523     /* all combinations documented as invalid succeeded */
1524     flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTTIME | FDTF_LONGTIME;
1525     SetLastError(0xdeadbeef);
1526     ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1527     ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1528     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1529
1530     flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_LONGDATE;
1531     SetLastError(0xdeadbeef);
1532     ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1533     ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1534     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1535
1536     flags =  FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE;
1537     SetLastError(0xdeadbeef);
1538     ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1539     ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1540     ok(GetLastError() == 0xdeadbeef ||
1541         broken(GetLastError() == ERROR_INVALID_FLAGS), /* Win9x/WinMe */
1542         "expected 0xdeadbeef, got %d\n", GetLastError());
1543
1544     /* now check returned strings */
1545     flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTTIME;
1546     ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1547     ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1548     ret = GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff2, sizeof(buff2));
1549     ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1550     ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1551
1552     flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGTIME;
1553     ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1554     ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1555     ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2));
1556     ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1557     ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1558
1559     /* both time flags */
1560     flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGTIME | FDTF_SHORTTIME;
1561     ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1562     ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1563     ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2));
1564     ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1565     ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1566
1567     flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE;
1568     ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1569     ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1570     ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1571     ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1572     ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1573
1574     flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE;
1575     ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1576     ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1577     ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1578     ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1579     ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1580
1581     /* both date flags */
1582     flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_SHORTDATE;
1583     ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1584     ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1585     ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1586     ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1587     ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1588
1589     /* various combinations of date/time flags */
1590     flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_SHORTTIME;
1591     ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1592     ok(ret == lstrlenA(buff)+1, "got %d, length %d\n", ret, lstrlenA(buff)+1);
1593     ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1594     ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1595     strcat(buff2, ", ");
1596     ret = GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3));
1597     ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1598     strcat(buff2, buff3);
1599     ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1600
1601     flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_LONGTIME;
1602     ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1603     ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1604     ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1605     ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1606     strcat(buff2, ", ");
1607     ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3));
1608     ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1609     strcat(buff2, buff3);
1610     ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1611
1612     flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_SHORTTIME;
1613     ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1614     ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1615     ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1616     ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1617     strcat(buff2, " ");
1618     ret = GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3));
1619     ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1620     strcat(buff2, buff3);
1621     ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1622
1623     flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_LONGTIME;
1624     ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1625     ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1626     ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1627     ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1628     strcat(buff2, " ");
1629     ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3));
1630     ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1631     strcat(buff2, buff3);
1632     ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1633 }
1634
1635 static void test_SHFormatDateTimeW(void)
1636 {
1637     FILETIME UNALIGNED filetime;
1638     WCHAR buff[100], buff2[100], buff3[100];
1639     SYSTEMTIME st;
1640     DWORD flags;
1641     INT ret;
1642     static const WCHAR spaceW[] = {' ',0};
1643     static const WCHAR commaW[] = {',',' ',0};
1644
1645     if(!pSHFormatDateTimeW)
1646     {
1647         win_skip("pSHFormatDateTimeW isn't available\n");
1648         return;
1649     }
1650
1651 if (0)
1652 {
1653     /* crashes on native */
1654     ret = pSHFormatDateTimeW(NULL, NULL, NULL, 0);
1655 }
1656
1657     GetLocalTime(&st);
1658     SystemTimeToFileTime(&st, &filetime);
1659     /* SHFormatDateTime expects input as utc */
1660     LocalFileTimeToFileTime(&filetime, &filetime);
1661
1662     /* no way to get required buffer length here */
1663     SetLastError(0xdeadbeef);
1664     ret = pSHFormatDateTimeW(&filetime, NULL, NULL, 0);
1665     ok(ret == 0, "got %d\n", ret);
1666     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1667
1668     SetLastError(0xdeadbeef);
1669     buff[0] = 'a'; buff[1] = 0;
1670     ret = pSHFormatDateTimeW(&filetime, NULL, buff, 0);
1671     ok(ret == 0, "got %d\n", ret);
1672     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1673     ok(buff[0] == 'a', "expected same string\n");
1674
1675     /* all combinations documented as invalid succeeded */
1676     flags = FDTF_SHORTTIME | FDTF_LONGTIME;
1677     SetLastError(0xdeadbeef);
1678     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1679     ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
1680     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1681
1682     flags = FDTF_SHORTDATE | FDTF_LONGDATE;
1683     SetLastError(0xdeadbeef);
1684     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1685     ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
1686     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1687
1688     flags = FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE;
1689     SetLastError(0xdeadbeef);
1690     buff[0] = 0; /* NT4 doesn't clear the buffer on failure */
1691     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1692     ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
1693     ok(GetLastError() == 0xdeadbeef ||
1694         broken(GetLastError() == ERROR_INVALID_FLAGS), /* Win9x/WinMe/NT4 */
1695         "expected 0xdeadbeef, got %d\n", GetLastError());
1696
1697     /* now check returned strings */
1698     flags = FDTF_SHORTTIME;
1699     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1700     ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
1701     SetLastError(0xdeadbeef);
1702     ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1703     if (ret == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1704     {
1705         win_skip("Needed W-functions are not implemented\n");
1706         return;
1707     }
1708     ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
1709     ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1710
1711     flags = FDTF_LONGTIME;
1712     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1713     ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
1714     ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1715     ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
1716     ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1717
1718     /* both time flags */
1719     flags = FDTF_LONGTIME | FDTF_SHORTTIME;
1720     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1721     ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
1722     ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1723     ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
1724     ok(lstrcmpW(buff, buff2) == 0, "expected equal string\n");
1725
1726     flags = FDTF_SHORTDATE;
1727     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1728     ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
1729     ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1730     ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
1731     ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1732
1733     flags = FDTF_LONGDATE;
1734     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1735     ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
1736     ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1737     ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
1738     ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1739
1740     /* both date flags */
1741     flags = FDTF_LONGDATE | FDTF_SHORTDATE;
1742     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1743     ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
1744     ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1745     ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
1746     ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1747
1748     /* various combinations of date/time flags */
1749     flags = FDTF_LONGDATE | FDTF_SHORTTIME;
1750     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1751     ok(ret == lstrlenW(buff)+1, "got %d, length %d\n", ret, lstrlenW(buff)+1);
1752     ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1753     ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
1754     lstrcatW(buff2, commaW);
1755     ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1756     ok(ret == lstrlenW(buff3)+1, "got %d\n", ret);
1757     lstrcatW(buff2, buff3);
1758     ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1759
1760     flags = FDTF_LONGDATE | FDTF_LONGTIME;
1761     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1762     ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
1763     ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1764     ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
1765     lstrcatW(buff2, commaW);
1766     ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1767     ok(ret == lstrlenW(buff3)+1, "got %d\n", ret);
1768     lstrcatW(buff2, buff3);
1769     ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1770
1771     flags = FDTF_SHORTDATE | FDTF_SHORTTIME;
1772     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1773     ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
1774     ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1775     ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
1776     lstrcatW(buff2, spaceW);
1777     ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1778     ok(ret == lstrlenW(buff3)+1, "got %d\n", ret);
1779     lstrcatW(buff2, buff3);
1780     ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1781
1782     flags = FDTF_SHORTDATE | FDTF_LONGTIME;
1783     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1784     ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
1785     ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1786     ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
1787     lstrcatW(buff2, spaceW);
1788     ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1789     ok(ret == lstrlenW(buff3)+1, "got %d\n", ret);
1790     lstrcatW(buff2, buff3);
1791     ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1792 }
1793
1794 static void test_SHGetObjectCompatFlags(void)
1795 {
1796     struct compat_value {
1797         CHAR nameA[30];
1798         DWORD value;
1799     };
1800
1801     struct compat_value values[] = {
1802         { "OTNEEDSSFCACHE", 0x1 },
1803         { "NO_WEBVIEW", 0x2 },
1804         { "UNBINDABLE", 0x4 },
1805         { "PINDLL", 0x8 },
1806         { "NEEDSFILESYSANCESTOR", 0x10 },
1807         { "NOTAFILESYSTEM", 0x20 },
1808         { "CTXMENU_NOVERBS", 0x40 },
1809         { "CTXMENU_LIMITEDQI", 0x80 },
1810         { "COCREATESHELLFOLDERONLY", 0x100 },
1811         { "NEEDSSTORAGEANCESTOR", 0x200 },
1812         { "NOLEGACYWEBVIEW", 0x400 },
1813         { "CTXMENU_XPQCMFLAGS", 0x1000 },
1814         { "NOIPROPERTYSTORE", 0x2000 }
1815     };
1816
1817     static const char compat_path[] = "Software\\Microsoft\\Windows\\CurrentVersion\\ShellCompatibility\\Objects";
1818     CHAR keyA[39]; /* {CLSID} */
1819     HKEY root;
1820     DWORD ret;
1821     int i;
1822
1823     if (!pSHGetObjectCompatFlags)
1824     {
1825         win_skip("SHGetObjectCompatFlags isn't available\n");
1826         return;
1827     }
1828
1829     /* null args */
1830     ret = pSHGetObjectCompatFlags(NULL, NULL);
1831     ok(ret == 0, "got %d\n", ret);
1832
1833     ret = RegOpenKeyA(HKEY_LOCAL_MACHINE, compat_path, &root);
1834     if (ret != ERROR_SUCCESS)
1835     {
1836         skip("No compatibility class data found\n");
1837         return;
1838     }
1839
1840     for (i = 0; RegEnumKeyA(root, i, keyA, sizeof(keyA)) == ERROR_SUCCESS; i++)
1841     {
1842         HKEY clsid_key;
1843
1844         if (RegOpenKeyA(root, keyA, &clsid_key) == ERROR_SUCCESS)
1845         {
1846             CHAR valueA[30];
1847             DWORD expected = 0, got, length = sizeof(valueA);
1848             CLSID clsid;
1849             int v;
1850
1851             for (v = 0; RegEnumValueA(clsid_key, v, valueA, &length, NULL, NULL, NULL, NULL) == ERROR_SUCCESS; v++)
1852             {
1853                 int j;
1854
1855                 for (j = 0; j < sizeof(values)/sizeof(struct compat_value); j++)
1856                     if (lstrcmpA(values[j].nameA, valueA) == 0)
1857                     {
1858                         expected |= values[j].value;
1859                         break;
1860                     }
1861
1862                 length = sizeof(valueA);
1863             }
1864
1865             pGUIDFromStringA(keyA, &clsid);
1866             got = pSHGetObjectCompatFlags(NULL, &clsid);
1867             ok(got == expected, "got 0x%08x, expected 0x%08x. Key %s\n", got, expected, keyA);
1868
1869             RegCloseKey(clsid_key);
1870         }
1871     }
1872
1873     RegCloseKey(root);
1874 }
1875
1876 static void init_pointers(void)
1877 {
1878 #define MAKEFUNC(f, ord) (p##f = (void*)GetProcAddress(hShlwapi, (LPSTR)(ord)))
1879     MAKEFUNC(SHAllocShared, 7);
1880     MAKEFUNC(SHLockShared, 8);
1881     MAKEFUNC(SHUnlockShared, 9);
1882     MAKEFUNC(SHFreeShared, 10);
1883     MAKEFUNC(GetAcceptLanguagesA, 14);
1884     MAKEFUNC(SHSetWindowBits, 165);
1885     MAKEFUNC(ConnectToConnectionPoint, 168);
1886     MAKEFUNC(SHSearchMapInt, 198);
1887     MAKEFUNC(GUIDFromStringA, 269);
1888     MAKEFUNC(SHPackDispParams, 282);
1889     MAKEFUNC(IConnectionPoint_InvokeWithCancel, 283);
1890     MAKEFUNC(IConnectionPoint_SimpleInvoke, 284);
1891     MAKEFUNC(SHFormatDateTimeA, 353);
1892     MAKEFUNC(SHFormatDateTimeW, 354);
1893     MAKEFUNC(SHGetObjectCompatFlags, 476);
1894     MAKEFUNC(SHPropertyBag_ReadLONG, 496);
1895 #undef MAKEFUNC
1896 }
1897
1898 START_TEST(ordinal)
1899 {
1900     hShlwapi = GetModuleHandleA("shlwapi.dll");
1901
1902     init_pointers();
1903
1904     hmlang = LoadLibraryA("mlang.dll");
1905     pLcidToRfc1766A = (void *)GetProcAddress(hmlang, "LcidToRfc1766A");
1906
1907     test_GetAcceptLanguagesA();
1908     test_SHSearchMapInt();
1909     test_alloc_shared();
1910     test_fdsa();
1911     test_GetShellSecurityDescriptor();
1912     test_SHPackDispParams();
1913     test_IConnectionPoint();
1914     test_SHPropertyBag_ReadLONG();
1915     test_SHSetWindowBits();
1916     test_SHFormatDateTimeA();
1917     test_SHFormatDateTimeW();
1918     test_SHGetObjectCompatFlags();
1919 }