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