shlwapi/tests: Use defined settings when testing GetAcceptLanguages.
[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
32 /* Function ptrs for ordinal calls */
33 static HMODULE hShlwapi;
34 static int (WINAPI *pSHSearchMapInt)(const int*,const int*,int,int);
35 static HRESULT (WINAPI *pGetAcceptLanguagesA)(LPSTR,LPDWORD);
36
37 static HANDLE (WINAPI *pSHAllocShared)(LPCVOID,DWORD,DWORD);
38 static LPVOID (WINAPI *pSHLockShared)(HANDLE,DWORD);
39 static BOOL   (WINAPI *pSHUnlockShared)(LPVOID);
40 static BOOL   (WINAPI *pSHFreeShared)(HANDLE,DWORD);
41 static HRESULT(WINAPIV *pSHPackDispParams)(DISPPARAMS*,VARIANTARG*,UINT,...);
42 static HRESULT(WINAPI *pIConnectionPoint_SimpleInvoke)(IConnectionPoint*,DISPID,DISPPARAMS*);
43 static HRESULT(WINAPI *pIConnectionPoint_InvokeWithCancel)(IConnectionPoint*,DISPID,DISPPARAMS*,DWORD,DWORD);
44 static HRESULT(WINAPI *pConnectToConnectionPoint)(IUnknown*,REFIID,BOOL,IUnknown*, LPDWORD,IConnectionPoint **);
45 static HRESULT(WINAPI *pSHPropertyBag_ReadLONG)(IPropertyBag *,LPCWSTR,LPLONG);
46
47 static HMODULE hmlang;
48 static HRESULT (WINAPI *pLcidToRfc1766A)(LCID, LPSTR, INT);
49
50 static const CHAR ie_international[] = {
51     'S','o','f','t','w','a','r','e','\\',
52     'M','i','c','r','o','s','o','f','t','\\',
53     'I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r','\\',
54     'I','n','t','e','r','n','a','t','i','o','n','a','l',0};
55 static const CHAR acceptlanguage[] = {
56     'A','c','c','e','p','t','L','a','n','g','u','a','g','e',0};
57
58
59 static void test_GetAcceptLanguagesA(void)
60 {
61     static LPCSTR table[] = {"de,en-gb;q=0.7,en;q=0.3",
62                              "de,en;q=0.3,en-gb;q=0.7", /* sorting is ignored */
63                              "winetest",    /* content is ignored */
64                              "de-de,de;q=0.5",
65                              "de",
66                              NULL};
67
68     DWORD exactsize;
69     char original[512];
70     char language[32];
71     char buffer[64];
72     HKEY hroot = NULL;
73     LONG res_query = ERROR_SUCCESS;
74     LONG lres;
75     HRESULT hr;
76     DWORD maxlen = sizeof(buffer) - 2;
77     DWORD len;
78     LCID lcid;
79     LPCSTR entry;
80     INT i = 0;
81
82     if (!pGetAcceptLanguagesA) {
83         win_skip("GetAcceptLanguagesA is not available\n");
84         return;
85     }
86
87     lcid = GetUserDefaultLCID();
88
89     /* Get the original Value */
90     lres = RegOpenKeyA(HKEY_CURRENT_USER, ie_international, &hroot);
91     if (lres) {
92         skip("RegOpenKey(%s) failed: %d\n", ie_international, lres);
93         return;
94     }
95     len = sizeof(original);
96     original[0] = 0;
97     res_query = RegQueryValueExA(hroot, acceptlanguage, 0, NULL, (PBYTE)original, &len);
98
99     RegDeleteValue(hroot, acceptlanguage);
100
101     /* Some windows versions use "lang-COUNTRY" as default */
102     memset(language, 0, sizeof(language));
103     len = GetLocaleInfoA(lcid, LOCALE_SISO639LANGNAME, language, sizeof(language));
104
105     if (len) {
106         lstrcat(language, "-");
107         memset(buffer, 0, sizeof(buffer));
108         len = GetLocaleInfoA(lcid, LOCALE_SISO3166CTRYNAME, buffer, sizeof(buffer) - len - 1);
109         lstrcat(language, buffer);
110     }
111     else
112     {
113         /* LOCALE_SNAME has additional parts in some languages. Try only as last chance */
114         memset(language, 0, sizeof(language));
115         len = GetLocaleInfoA(lcid, LOCALE_SNAME, language, sizeof(language));
116     }
117
118     /* get the default value */
119     len = maxlen;
120     memset(buffer, '#', maxlen);
121     buffer[maxlen] = 0;
122     hr = pGetAcceptLanguagesA( buffer, &len);
123
124     if (hr != S_OK) {
125         win_skip("GetAcceptLanguagesA failed with 0x%x\n", hr);
126         goto restore_original;
127     }
128
129     if (lstrcmpA(buffer, language)) {
130         /* some windows versions use "lang" or "lang-country" as default */
131         language[0] = 0;
132         if (pLcidToRfc1766A) {
133             hr = pLcidToRfc1766A(lcid, language, sizeof(language));
134             ok(hr == S_OK, "LcidToRfc1766A returned 0x%x and %s\n", hr, language);
135         }
136     }
137
138     ok(!lstrcmpA(buffer, language),
139         "have '%s' (searching for '%s')\n", language, buffer);
140
141     if (lstrcmpA(buffer, language)) {
142         win_skip("no more ideas, how to build the default language '%s'\n", buffer);
143         goto restore_original;
144     }
145
146     trace("detected default: %s\n", language);
147     while ((entry = table[i])) {
148
149         exactsize = lstrlenA(entry);
150
151         lres = RegSetValueExA(hroot, acceptlanguage, 0, REG_SZ, (const BYTE *) entry, exactsize + 1);
152         ok(!lres, "got %d for RegSetValueExA: %s\n", lres, entry);
153
154         /* len includes space for the terminating 0 before vista/w2k8 */
155         len = exactsize + 2;
156         memset(buffer, '#', maxlen);
157         buffer[maxlen] = 0;
158         hr = pGetAcceptLanguagesA( buffer, &len);
159         ok(((hr == E_INVALIDARG) && (len == 0)) ||
160             (SUCCEEDED(hr) &&
161             ((len == exactsize) || (len == exactsize+1)) &&
162             !lstrcmpA(buffer, entry)),
163             "+2_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
164
165         len = exactsize + 1;
166         memset(buffer, '#', maxlen);
167         buffer[maxlen] = 0;
168         hr = pGetAcceptLanguagesA( buffer, &len);
169         ok(((hr == E_INVALIDARG) && (len == 0)) ||
170             (SUCCEEDED(hr) &&
171             ((len == exactsize) || (len == exactsize+1)) &&
172             !lstrcmpA(buffer, entry)),
173             "+1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
174
175         len = exactsize;
176         memset(buffer, '#', maxlen);
177         buffer[maxlen] = 0;
178         hr = pGetAcceptLanguagesA( buffer, &len);
179
180         /* There is no space for the string in the registry.
181            When the buffer is large enough, the default language is returned
182
183            When the buffer is to small for that fallback, win7_32 and w2k8_64
184            and above fail with HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), but
185            recent os succeed and return a partial result while
186            older os succeed and overflow the buffer */
187
188         ok(((hr == E_INVALIDARG) && (len == 0)) ||
189             (((hr == S_OK) && !lstrcmpA(buffer, language)  && (len == lstrlenA(language))) ||
190             ((hr == S_OK) && !memcmp(buffer, language, len)) ||
191             ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len)),
192             "==_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
193
194         if (exactsize > 1) {
195             len = exactsize - 1;
196             memset(buffer, '#', maxlen);
197             buffer[maxlen] = 0;
198             hr = pGetAcceptLanguagesA( buffer, &len);
199             ok(((hr == E_INVALIDARG) && (len == 0)) ||
200                 (((hr == S_OK) && !lstrcmpA(buffer, language)  && (len == lstrlenA(language))) ||
201                 ((hr == S_OK) && !memcmp(buffer, language, len)) ||
202                 ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len)),
203                 "-1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
204         }
205
206         len = 1;
207         memset(buffer, '#', maxlen);
208         buffer[maxlen] = 0;
209         hr = pGetAcceptLanguagesA( buffer, &len);
210         ok(((hr == E_INVALIDARG) && (len == 0)) ||
211             (((hr == S_OK) && !lstrcmpA(buffer, language)  && (len == lstrlenA(language))) ||
212             ((hr == S_OK) && !memcmp(buffer, language, len)) ||
213             ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len)),
214             "=1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
215
216         len = maxlen;
217         hr = pGetAcceptLanguagesA( NULL, &len);
218
219         /* w2k3 and below: E_FAIL and untouched len,
220            since w2k8: S_OK and needed size (excluding 0) */
221         ok( ((hr == S_OK) && (len == exactsize)) ||
222             ((hr == E_FAIL) && (len == maxlen)),
223             "NULL,max #%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
224
225         i++;
226     }
227
228     /* without a value in the registry, a default language is returned */
229     RegDeleteValue(hroot, acceptlanguage);
230
231     len = maxlen;
232     memset(buffer, '#', maxlen);
233     buffer[maxlen] = 0;
234     hr = pGetAcceptLanguagesA( buffer, &len);
235     ok( ((hr == S_OK) && (len == lstrlenA(language))),
236         "max: got 0x%x with %d and %s (expected S_OK with %d and '%s'\n",
237         hr, len, buffer, lstrlenA(language), language);
238
239     len = 2;
240     memset(buffer, '#', maxlen);
241     buffer[maxlen] = 0;
242     hr = pGetAcceptLanguagesA( buffer, &len);
243     ok( (((hr == S_OK) || (hr == E_INVALIDARG)) && !memcmp(buffer, language, len)) ||
244         ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len),
245         "=2: got 0x%x with %d and %s\n", hr, len, buffer);
246
247     len = 1;
248     memset(buffer, '#', maxlen);
249     buffer[maxlen] = 0;
250     hr = pGetAcceptLanguagesA( buffer, &len);
251     /* When the buffer is to small, win7_32 and w2k8_64 and above fail with
252        HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), other versions suceed
253        and return a partial 0 terminated result while other versions
254        fail with E_INVALIDARG and return a partial unterminated result */
255     ok( (((hr == S_OK) || (hr == E_INVALIDARG)) && !memcmp(buffer, language, len)) ||
256         ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len),
257         "=1: got 0x%x with %d and %s\n", hr, len, buffer);
258
259     len = 0;
260     memset(buffer, '#', maxlen);
261     buffer[maxlen] = 0;
262     hr = pGetAcceptLanguagesA( buffer, &len);
263     /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG */
264     ok((hr == E_FAIL) || (hr == E_INVALIDARG),
265         "got 0x%x (expected E_FAIL or E_INVALIDARG)\n", hr);
266
267     memset(buffer, '#', maxlen);
268     buffer[maxlen] = 0;
269     hr = pGetAcceptLanguagesA( buffer, NULL);
270     /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG */
271     ok((hr == E_FAIL) || (hr == E_INVALIDARG),
272         "got 0x%x (expected E_FAIL or E_INVALIDARG)\n", hr);
273
274
275     hr = pGetAcceptLanguagesA( NULL, 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 restore_original:
281     if (!res_query) {
282         len = lstrlenA(original);
283         lres = RegSetValueExA(hroot, acceptlanguage, 0, REG_SZ, (const BYTE *) original, len ? len + 1: 0);
284         ok(!lres, "RegSetValueEx(%s) failed: %d\n", original, lres);
285     }
286     else
287     {
288         RegDeleteValue(hroot, acceptlanguage);
289     }
290     RegCloseKey(hroot);
291 }
292
293 static void test_SHSearchMapInt(void)
294 {
295   int keys[8], values[8];
296   int i = 0;
297
298   if (!pSHSearchMapInt)
299     return;
300
301   memset(keys, 0, sizeof(keys));
302   memset(values, 0, sizeof(values));
303   keys[0] = 99; values[0] = 101;
304
305   /* NULL key/value lists crash native, so skip testing them */
306
307   /* 1 element */
308   i = pSHSearchMapInt(keys, values, 1, keys[0]);
309   ok(i == values[0], "Len 1, expected %d, got %d\n", values[0], i);
310
311   /* Key doesn't exist */
312   i = pSHSearchMapInt(keys, values, 1, 100);
313   ok(i == -1, "Len 1 - bad key, expected -1, got %d\n", i);
314
315   /* Len = 0 => not found */
316   i = pSHSearchMapInt(keys, values, 0, keys[0]);
317   ok(i == -1, "Len 1 - passed len 0, expected -1, got %d\n", i);
318
319   /* 2 elements, len = 1 */
320   keys[1] = 98; values[1] = 102;
321   i = pSHSearchMapInt(keys, values, 1, keys[1]);
322   ok(i == -1, "Len 1 - array len 2, expected -1, got %d\n", i);
323
324   /* 2 elements, len = 2 */
325   i = pSHSearchMapInt(keys, values, 2, keys[1]);
326   ok(i == values[1], "Len 2, expected %d, got %d\n", values[1], i);
327
328   /* Searches forward */
329   keys[2] = 99; values[2] = 103;
330   i = pSHSearchMapInt(keys, values, 3, keys[0]);
331   ok(i == values[0], "Len 3, expected %d, got %d\n", values[0], i);
332 }
333
334 static void test_alloc_shared(void)
335 {
336     DWORD procid;
337     HANDLE hmem;
338     int val;
339     int* p;
340     BOOL ret;
341
342     procid=GetCurrentProcessId();
343     hmem=pSHAllocShared(NULL,10,procid);
344     ok(hmem!=NULL,"SHAllocShared(NULL...) failed: %u\n", GetLastError());
345     ret = pSHFreeShared(hmem, procid);
346     ok( ret, "SHFreeShared failed: %u\n", GetLastError());
347
348     val=0x12345678;
349     hmem=pSHAllocShared(&val,4,procid);
350     ok(hmem!=NULL,"SHAllocShared(NULL...) failed: %u\n", GetLastError());
351
352     p=pSHLockShared(hmem,procid);
353     ok(p!=NULL,"SHLockShared failed: %u\n", GetLastError());
354     if (p!=NULL)
355         ok(*p==val,"Wrong value in shared memory: %d instead of %d\n",*p,val);
356     ret = pSHUnlockShared(p);
357     ok( ret, "SHUnlockShared failed: %u\n", GetLastError());
358
359     ret = pSHFreeShared(hmem, procid);
360     ok( ret, "SHFreeShared failed: %u\n", GetLastError());
361 }
362
363 static void test_fdsa(void)
364 {
365     typedef struct
366     {
367         DWORD num_items;       /* Number of elements inserted */
368         void *mem;             /* Ptr to array */
369         DWORD blocks_alloced;  /* Number of elements allocated */
370         BYTE inc;              /* Number of elements to grow by when we need to expand */
371         BYTE block_size;       /* Size in bytes of an element */
372         BYTE flags;            /* Flags */
373     } FDSA_info;
374
375     BOOL (WINAPI *pFDSA_Initialize)(DWORD block_size, DWORD inc, FDSA_info *info, void *mem,
376                                     DWORD init_blocks);
377     BOOL (WINAPI *pFDSA_Destroy)(FDSA_info *info);
378     DWORD (WINAPI *pFDSA_InsertItem)(FDSA_info *info, DWORD where, const void *block);
379     BOOL (WINAPI *pFDSA_DeleteItem)(FDSA_info *info, DWORD where);
380
381     FDSA_info info;
382     int block_size = 10, init_blocks = 4, inc = 2;
383     DWORD ret;
384     char *mem;
385
386     pFDSA_Initialize = (void *)GetProcAddress(hShlwapi, (LPSTR)208);
387     pFDSA_Destroy    = (void *)GetProcAddress(hShlwapi, (LPSTR)209);
388     pFDSA_InsertItem = (void *)GetProcAddress(hShlwapi, (LPSTR)210);
389     pFDSA_DeleteItem = (void *)GetProcAddress(hShlwapi, (LPSTR)211);
390
391     mem = HeapAlloc(GetProcessHeap(), 0, block_size * init_blocks);
392     memset(&info, 0, sizeof(info));
393
394     ok(pFDSA_Initialize(block_size, inc, &info, mem, init_blocks), "FDSA_Initialize rets FALSE\n");
395     ok(info.num_items == 0, "num_items = %d\n", info.num_items);
396     ok(info.mem == mem, "mem = %p\n", info.mem);
397     ok(info.blocks_alloced == init_blocks, "blocks_alloced = %d\n", info.blocks_alloced);
398     ok(info.inc == inc, "inc = %d\n", info.inc);
399     ok(info.block_size == block_size, "block_size = %d\n", info.block_size);
400     ok(info.flags == 0, "flags = %d\n", info.flags);
401
402     ret = pFDSA_InsertItem(&info, 1234, "1234567890");
403     ok(ret == 0, "ret = %d\n", ret);
404     ok(info.num_items == 1, "num_items = %d\n", info.num_items);
405     ok(info.mem == mem, "mem = %p\n", info.mem);
406     ok(info.blocks_alloced == init_blocks, "blocks_alloced = %d\n", info.blocks_alloced);
407     ok(info.inc == inc, "inc = %d\n", info.inc);
408     ok(info.block_size == block_size, "block_size = %d\n", info.block_size);
409     ok(info.flags == 0, "flags = %d\n", info.flags);
410
411     ret = pFDSA_InsertItem(&info, 1234, "abcdefghij");
412     ok(ret == 1, "ret = %d\n", ret);
413
414     ret = pFDSA_InsertItem(&info, 1, "klmnopqrst");
415     ok(ret == 1, "ret = %d\n", ret);
416
417     ret = pFDSA_InsertItem(&info, 0, "uvwxyzABCD");
418     ok(ret == 0, "ret = %d\n", ret);
419     ok(info.mem == mem, "mem = %p\n", info.mem);
420     ok(info.flags == 0, "flags = %d\n", info.flags);
421
422     /* This next InsertItem will cause shlwapi to allocate its own mem buffer */
423     ret = pFDSA_InsertItem(&info, 0, "EFGHIJKLMN");
424     ok(ret == 0, "ret = %d\n", ret);
425     ok(info.mem != mem, "mem = %p\n", info.mem);
426     ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %d\n", info.blocks_alloced);
427     ok(info.flags == 0x1, "flags = %d\n", info.flags);
428
429     ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCD1234567890klmnopqrstabcdefghij", 50), "mem %s\n", (char*)info.mem);
430
431     ok(pFDSA_DeleteItem(&info, 2), "rets FALSE\n");
432     ok(info.mem != mem, "mem = %p\n", info.mem);
433     ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %d\n", info.blocks_alloced);
434     ok(info.flags == 0x1, "flags = %d\n", info.flags);
435
436     ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCDklmnopqrstabcdefghij", 40), "mem %s\n", (char*)info.mem);
437
438     ok(pFDSA_DeleteItem(&info, 3), "rets FALSE\n");
439     ok(info.mem != mem, "mem = %p\n", info.mem);
440     ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %d\n", info.blocks_alloced);
441     ok(info.flags == 0x1, "flags = %d\n", info.flags);
442
443     ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCDklmnopqrst", 30), "mem %s\n", (char*)info.mem);
444
445     ok(!pFDSA_DeleteItem(&info, 4), "does not ret FALSE\n");
446
447     /* As shlwapi has allocated memory internally, Destroy will ret FALSE */
448     ok(!pFDSA_Destroy(&info), "FDSA_Destroy does not ret FALSE\n");
449
450
451     /* When Initialize is called with inc = 0, set it to 1 */
452     ok(pFDSA_Initialize(block_size, 0, &info, mem, init_blocks), "FDSA_Initialize rets FALSE\n");
453     ok(info.inc == 1, "inc = %d\n", info.inc);
454
455     /* This time, because shlwapi hasn't had to allocate memory
456        internally, Destroy rets non-zero */
457     ok(pFDSA_Destroy(&info), "FDSA_Destroy rets FALSE\n");
458
459
460     HeapFree(GetProcessHeap(), 0, mem);
461 }
462
463
464 typedef struct SHELL_USER_SID {
465     SID_IDENTIFIER_AUTHORITY sidAuthority;
466     DWORD                    dwUserGroupID;
467     DWORD                    dwUserID;
468 } SHELL_USER_SID, *PSHELL_USER_SID;
469 typedef struct SHELL_USER_PERMISSION {
470     SHELL_USER_SID susID;
471     DWORD          dwAccessType;
472     BOOL           fInherit;
473     DWORD          dwAccessMask;
474     DWORD          dwInheritMask;
475     DWORD          dwInheritAccessMask;
476 } SHELL_USER_PERMISSION, *PSHELL_USER_PERMISSION;
477 static void test_GetShellSecurityDescriptor(void)
478 {
479     SHELL_USER_PERMISSION supCurrentUserFull = {
480         { {SECURITY_NULL_SID_AUTHORITY}, 0, 0 },
481         ACCESS_ALLOWED_ACE_TYPE, FALSE,
482         GENERIC_ALL, 0, 0 };
483 #define MY_INHERITANCE 0xBE /* invalid value to proof behavior */
484     SHELL_USER_PERMISSION supEveryoneDenied = {
485         { {SECURITY_WORLD_SID_AUTHORITY}, SECURITY_WORLD_RID, 0 },
486         ACCESS_DENIED_ACE_TYPE, TRUE,
487         GENERIC_WRITE, MY_INHERITANCE | 0xDEADBA00, GENERIC_READ };
488     PSHELL_USER_PERMISSION rgsup[2] = {
489         &supCurrentUserFull, &supEveryoneDenied,
490     };
491     SECURITY_DESCRIPTOR* psd;
492     SECURITY_DESCRIPTOR* (WINAPI*pGetShellSecurityDescriptor)(PSHELL_USER_PERMISSION*,int);
493
494     pGetShellSecurityDescriptor=(void*)GetProcAddress(hShlwapi,(char*)475);
495
496     if(!pGetShellSecurityDescriptor)
497     {
498         win_skip("GetShellSecurityDescriptor not available\n");
499         return;
500     }
501
502     psd = pGetShellSecurityDescriptor(NULL, 2);
503     ok(psd==NULL ||
504        broken(psd==INVALID_HANDLE_VALUE), /* IE5 */
505        "GetShellSecurityDescriptor should fail\n");
506     psd = pGetShellSecurityDescriptor(rgsup, 0);
507     ok(psd==NULL, "GetShellSecurityDescriptor should fail\n");
508
509     SetLastError(0xdeadbeef);
510     psd = pGetShellSecurityDescriptor(rgsup, 2);
511     if (psd == NULL && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
512     {
513         /* The previous calls to GetShellSecurityDescriptor don't set the last error */
514         win_skip("GetShellSecurityDescriptor is not implemented\n");
515         return;
516     }
517     if (psd==INVALID_HANDLE_VALUE)
518     {
519         win_skip("GetShellSecurityDescriptor is broken on IE5\n");
520         return;
521     }
522     ok(psd!=NULL, "GetShellSecurityDescriptor failed\n");
523     if (psd!=NULL)
524     {
525         BOOL bHasDacl = FALSE, bDefaulted;
526         PACL pAcl;
527         DWORD dwRev;
528         SECURITY_DESCRIPTOR_CONTROL control;
529
530         ok(IsValidSecurityDescriptor(psd), "returned value is not valid SD\n");
531
532         ok(GetSecurityDescriptorControl(psd, &control, &dwRev),
533                 "GetSecurityDescriptorControl failed with error %u\n", GetLastError());
534         ok(0 == (control & SE_SELF_RELATIVE), "SD should be absolute\n");
535
536         ok(GetSecurityDescriptorDacl(psd, &bHasDacl, &pAcl, &bDefaulted), 
537             "GetSecurityDescriptorDacl failed with error %u\n", GetLastError());
538
539         ok(bHasDacl, "SD has no DACL\n");
540         if (bHasDacl)
541         {
542             ok(!bDefaulted, "DACL should not be defaulted\n");
543
544             ok(pAcl != NULL, "NULL DACL!\n");
545             if (pAcl != NULL)
546             {
547                 ACL_SIZE_INFORMATION asiSize;
548
549                 ok(IsValidAcl(pAcl), "DACL is not valid\n");
550
551                 ok(GetAclInformation(pAcl, &asiSize, sizeof(asiSize), AclSizeInformation),
552                         "GetAclInformation failed with error %u\n", GetLastError());
553
554                 ok(asiSize.AceCount == 3, "Incorrect number of ACEs: %d entries\n", asiSize.AceCount);
555                 if (asiSize.AceCount == 3)
556                 {
557                     ACCESS_ALLOWED_ACE *paaa; /* will use for DENIED too */
558
559                     ok(GetAce(pAcl, 0, (LPVOID*)&paaa), "GetAce failed with error %u\n", GetLastError());
560                     ok(paaa->Header.AceType == ACCESS_ALLOWED_ACE_TYPE, 
561                             "Invalid ACE type %d\n", paaa->Header.AceType); 
562                     ok(paaa->Header.AceFlags == 0, "Invalid ACE flags %x\n", paaa->Header.AceFlags);
563                     ok(paaa->Mask == GENERIC_ALL, "Invalid ACE mask %x\n", paaa->Mask);
564
565                     ok(GetAce(pAcl, 1, (LPVOID*)&paaa), "GetAce failed with error %u\n", GetLastError());
566                     ok(paaa->Header.AceType == ACCESS_DENIED_ACE_TYPE, 
567                             "Invalid ACE type %d\n", paaa->Header.AceType); 
568                     /* first one of two ACEs generated from inheritable entry - without inheritance */
569                     ok(paaa->Header.AceFlags == 0, "Invalid ACE flags %x\n", paaa->Header.AceFlags);
570                     ok(paaa->Mask == GENERIC_WRITE, "Invalid ACE mask %x\n", paaa->Mask);
571
572                     ok(GetAce(pAcl, 2, (LPVOID*)&paaa), "GetAce failed with error %u\n", GetLastError());
573                     ok(paaa->Header.AceType == ACCESS_DENIED_ACE_TYPE, 
574                             "Invalid ACE type %d\n", paaa->Header.AceType); 
575                     /* second ACE - with inheritance */
576                     ok(paaa->Header.AceFlags == MY_INHERITANCE,
577                             "Invalid ACE flags %x\n", paaa->Header.AceFlags);
578                     ok(paaa->Mask == GENERIC_READ, "Invalid ACE mask %x\n", paaa->Mask);
579                 }
580             }
581         }
582
583         LocalFree(psd);
584     }
585 }
586
587 static void test_SHPackDispParams(void)
588 {
589     DISPPARAMS params;
590     VARIANT vars[10];
591     HRESULT hres;
592
593     if(!pSHPackDispParams)
594         win_skip("SHPackSidpParams not available\n");
595
596     memset(&params, 0xc0, sizeof(params));
597     memset(vars, 0xc0, sizeof(vars));
598     hres = pSHPackDispParams(&params, vars, 1, VT_I4, 0xdeadbeef);
599     ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres);
600     ok(params.cArgs == 1, "params.cArgs = %d\n", params.cArgs);
601     ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
602     ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
603     ok(params.rgvarg == vars, "params.rgvarg = %p\n", params.rgvarg);
604     ok(V_VT(vars) == VT_I4, "V_VT(var) = %d\n", V_VT(vars));
605     ok(V_I4(vars) == 0xdeadbeef, "failed %x\n", V_I4(vars));
606
607     memset(&params, 0xc0, sizeof(params));
608     hres = pSHPackDispParams(&params, NULL, 0, 0);
609     ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres);
610     ok(params.cArgs == 0, "params.cArgs = %d\n", params.cArgs);
611     ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
612     ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
613     ok(params.rgvarg == NULL, "params.rgvarg = %p\n", params.rgvarg);
614
615     memset(vars, 0xc0, sizeof(vars));
616     memset(&params, 0xc0, sizeof(params));
617     hres = pSHPackDispParams(&params, vars, 4, VT_BSTR, (void*)0xdeadbeef, VT_EMPTY, 10,
618             VT_I4, 100, VT_DISPATCH, (void*)0xdeadbeef);
619     ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres);
620     ok(params.cArgs == 4, "params.cArgs = %d\n", params.cArgs);
621     ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
622     ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
623     ok(params.rgvarg == vars, "params.rgvarg = %p\n", params.rgvarg);
624     ok(V_VT(vars) == VT_DISPATCH, "V_VT(vars[0]) = %x\n", V_VT(vars));
625     ok(V_I4(vars) == 0xdeadbeef, "V_I4(vars[0]) = %x\n", V_I4(vars));
626     ok(V_VT(vars+1) == VT_I4, "V_VT(vars[1]) = %d\n", V_VT(vars+1));
627     ok(V_I4(vars+1) == 100, "V_I4(vars[1]) = %x\n", V_I4(vars+1));
628     ok(V_VT(vars+2) == VT_I4, "V_VT(vars[2]) = %d\n", V_VT(vars+2));
629     ok(V_I4(vars+2) == 10, "V_I4(vars[2]) = %x\n", V_I4(vars+2));
630     ok(V_VT(vars+3) == VT_BSTR, "V_VT(vars[3]) = %d\n", V_VT(vars+3));
631     ok(V_BSTR(vars+3) == (void*)0xdeadbeef, "V_BSTR(vars[3]) = %p\n", V_BSTR(vars+3));
632 }
633
634 typedef struct _disp
635 {
636     const IDispatchVtbl *vtbl;
637     LONG   refCount;
638 } Disp;
639
640 typedef struct _contain
641 {
642     const IConnectionPointContainerVtbl *vtbl;
643     LONG   refCount;
644
645     UINT  ptCount;
646     IConnectionPoint **pt;
647 } Contain;
648
649 typedef struct _cntptn
650 {
651     const IConnectionPointVtbl *vtbl;
652     LONG refCount;
653
654     Contain *container;
655     GUID  id;
656     UINT  sinkCount;
657     IUnknown **sink;
658 } ConPt;
659
660 typedef struct _enum
661 {
662     const IEnumConnectionsVtbl *vtbl;
663     LONG   refCount;
664
665     UINT idx;
666     ConPt *pt;
667 } EnumCon;
668
669 typedef struct _enumpt
670 {
671     const IEnumConnectionPointsVtbl *vtbl;
672     LONG   refCount;
673
674     int idx;
675     Contain *container;
676 } EnumPt;
677
678
679 static HRESULT WINAPI Disp_QueryInterface(
680         IDispatch* This,
681         REFIID riid,
682         void **ppvObject)
683 {
684     *ppvObject = NULL;
685
686     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDispatch))
687     {
688         *ppvObject = This;
689     }
690
691     if (*ppvObject)
692     {
693         IUnknown_AddRef(This);
694         return S_OK;
695     }
696
697     trace("no interface\n");
698     return E_NOINTERFACE;
699 }
700
701 static ULONG WINAPI Disp_AddRef(IDispatch* This)
702 {
703     Disp *iface = (Disp*)This;
704     return InterlockedIncrement(&iface->refCount);
705 }
706
707 static ULONG WINAPI Disp_Release(IDispatch* This)
708 {
709     Disp *iface = (Disp*)This;
710     ULONG ret;
711
712     ret = InterlockedDecrement(&iface->refCount);
713     if (ret == 0)
714         HeapFree(GetProcessHeap(),0,This);
715     return ret;
716 }
717
718 static HRESULT WINAPI Disp_GetTypeInfoCount(
719         IDispatch* This,
720         UINT *pctinfo)
721 {
722     return ERROR_SUCCESS;
723 }
724
725 static HRESULT WINAPI Disp_GetTypeInfo(
726         IDispatch* This,
727         UINT iTInfo,
728         LCID lcid,
729         ITypeInfo **ppTInfo)
730 {
731     return ERROR_SUCCESS;
732 }
733
734 static HRESULT WINAPI Disp_GetIDsOfNames(
735         IDispatch* This,
736         REFIID riid,
737         LPOLESTR *rgszNames,
738         UINT cNames,
739         LCID lcid,
740         DISPID *rgDispId)
741 {
742     return ERROR_SUCCESS;
743 }
744
745 static HRESULT WINAPI Disp_Invoke(
746         IDispatch* This,
747         DISPID dispIdMember,
748         REFIID riid,
749         LCID lcid,
750         WORD wFlags,
751         DISPPARAMS *pDispParams,
752         VARIANT *pVarResult,
753         EXCEPINFO *pExcepInfo,
754         UINT *puArgErr)
755 {
756     trace("%p %x %p %x %x %p %p %p %p\n",This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
757
758     ok(dispIdMember == 0xa0 || dispIdMember == 0xa1, "Unknown dispIdMember\n");
759     ok(pDispParams != NULL, "Invoked with NULL pDispParams\n");
760     ok(wFlags == DISPATCH_METHOD, "Wrong flags %x\n",wFlags);
761     ok(lcid == 0,"Wrong lcid %x\n",lcid);
762     if (dispIdMember == 0xa0)
763     {
764         ok(pDispParams->cArgs == 0, "params.cArgs = %d\n", pDispParams->cArgs);
765         ok(pDispParams->cNamedArgs == 0, "params.cNamedArgs = %d\n", pDispParams->cArgs);
766         ok(pDispParams->rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", pDispParams->rgdispidNamedArgs);
767         ok(pDispParams->rgvarg == NULL, "params.rgvarg = %p\n", pDispParams->rgvarg);
768     }
769     else if (dispIdMember == 0xa1)
770     {
771         ok(pDispParams->cArgs == 2, "params.cArgs = %d\n", pDispParams->cArgs);
772         ok(pDispParams->cNamedArgs == 0, "params.cNamedArgs = %d\n", pDispParams->cArgs);
773         ok(pDispParams->rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", pDispParams->rgdispidNamedArgs);
774         ok(V_VT(pDispParams->rgvarg) == VT_BSTR, "V_VT(var) = %d\n", V_VT(pDispParams->rgvarg));
775         ok(V_I4(pDispParams->rgvarg) == 0xdeadcafe , "failed %p\n", V_BSTR(pDispParams->rgvarg));
776         ok(V_VT(pDispParams->rgvarg+1) == VT_I4, "V_VT(var) = %d\n", V_VT(pDispParams->rgvarg+1));
777         ok(V_I4(pDispParams->rgvarg+1) == 0xdeadbeef, "failed %x\n", V_I4(pDispParams->rgvarg+1));
778     }
779
780     return ERROR_SUCCESS;
781 }
782
783 static const IDispatchVtbl disp_vtbl = {
784     Disp_QueryInterface,
785     Disp_AddRef,
786     Disp_Release,
787
788     Disp_GetTypeInfoCount,
789     Disp_GetTypeInfo,
790     Disp_GetIDsOfNames,
791     Disp_Invoke
792 };
793
794 static HRESULT WINAPI Enum_QueryInterface(
795         IEnumConnections* This,
796         REFIID riid,
797         void **ppvObject)
798 {
799     *ppvObject = NULL;
800
801     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumConnections))
802     {
803         *ppvObject = This;
804     }
805
806     if (*ppvObject)
807     {
808         IUnknown_AddRef(This);
809         return S_OK;
810     }
811
812     trace("no interface\n");
813     return E_NOINTERFACE;
814 }
815
816 static ULONG WINAPI Enum_AddRef(IEnumConnections* This)
817 {
818     EnumCon *iface = (EnumCon*)This;
819     return InterlockedIncrement(&iface->refCount);
820 }
821
822 static ULONG WINAPI Enum_Release(IEnumConnections* This)
823 {
824     EnumCon *iface = (EnumCon*)This;
825     ULONG ret;
826
827     ret = InterlockedDecrement(&iface->refCount);
828     if (ret == 0)
829         HeapFree(GetProcessHeap(),0,This);
830     return ret;
831 }
832
833 static HRESULT WINAPI Enum_Next(
834         IEnumConnections* This,
835         ULONG cConnections,
836         LPCONNECTDATA rgcd,
837         ULONG *pcFetched)
838 {
839     EnumCon *iface = (EnumCon*)This;
840
841     if (cConnections > 0 && iface->idx < iface->pt->sinkCount)
842     {
843         rgcd->pUnk = iface->pt->sink[iface->idx];
844         IUnknown_AddRef(iface->pt->sink[iface->idx]);
845         rgcd->dwCookie=0xff;
846         if (pcFetched)
847             *pcFetched = 1;
848         iface->idx++;
849         return S_OK;
850     }
851
852     return E_FAIL;
853 }
854
855 static HRESULT WINAPI Enum_Skip(
856         IEnumConnections* This,
857         ULONG cConnections)
858 {
859     return E_FAIL;
860 }
861
862 static HRESULT WINAPI Enum_Reset(
863         IEnumConnections* This)
864 {
865     return E_FAIL;
866 }
867
868 static HRESULT WINAPI Enum_Clone(
869         IEnumConnections* This,
870         IEnumConnections **ppEnum)
871 {
872     return E_FAIL;
873 }
874
875 static const IEnumConnectionsVtbl enum_vtbl = {
876
877     Enum_QueryInterface,
878     Enum_AddRef,
879     Enum_Release,
880     Enum_Next,
881     Enum_Skip,
882     Enum_Reset,
883     Enum_Clone
884 };
885
886 static HRESULT WINAPI ConPt_QueryInterface(
887         IConnectionPoint* This,
888         REFIID riid,
889         void **ppvObject)
890 {
891     *ppvObject = NULL;
892
893     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IConnectionPoint))
894     {
895         *ppvObject = This;
896     }
897
898     if (*ppvObject)
899     {
900         IUnknown_AddRef(This);
901         return S_OK;
902     }
903
904     trace("no interface\n");
905     return E_NOINTERFACE;
906 }
907
908 static ULONG WINAPI ConPt_AddRef(
909         IConnectionPoint* This)
910 {
911     ConPt *iface = (ConPt*)This;
912     return InterlockedIncrement(&iface->refCount);
913 }
914
915 static ULONG WINAPI ConPt_Release(
916         IConnectionPoint* This)
917 {
918     ConPt *iface = (ConPt*)This;
919     ULONG ret;
920
921     ret = InterlockedDecrement(&iface->refCount);
922     if (ret == 0)
923     {
924         if (iface->sinkCount > 0)
925         {
926             int i;
927             for (i = 0; i < iface->sinkCount; i++)
928             {
929                 if (iface->sink[i])
930                     IUnknown_Release(iface->sink[i]);
931             }
932             HeapFree(GetProcessHeap(),0,iface->sink);
933         }
934         HeapFree(GetProcessHeap(),0,This);
935     }
936     return ret;
937 }
938
939 static HRESULT WINAPI ConPt_GetConnectionInterface(
940         IConnectionPoint* This,
941         IID *pIID)
942 {
943     static int i = 0;
944     ConPt *iface = (ConPt*)This;
945     if (i==0)
946     {
947         i++;
948         return E_FAIL;
949     }
950     else
951         memcpy(pIID,&iface->id,sizeof(GUID));
952     return S_OK;
953 }
954
955 static HRESULT WINAPI ConPt_GetConnectionPointContainer(
956         IConnectionPoint* This,
957         IConnectionPointContainer **ppCPC)
958 {
959     ConPt *iface = (ConPt*)This;
960
961     *ppCPC = (IConnectionPointContainer*)iface->container;
962     return S_OK;
963 }
964
965 static HRESULT WINAPI ConPt_Advise(
966         IConnectionPoint* This,
967         IUnknown *pUnkSink,
968         DWORD *pdwCookie)
969 {
970     ConPt *iface = (ConPt*)This;
971
972     if (iface->sinkCount == 0)
973         iface->sink = HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown*));
974     else
975         iface->sink = HeapReAlloc(GetProcessHeap(),0,iface->sink,sizeof(IUnknown*)*(iface->sinkCount+1));
976     iface->sink[iface->sinkCount] = pUnkSink;
977     IUnknown_AddRef(pUnkSink);
978     iface->sinkCount++;
979     *pdwCookie = iface->sinkCount;
980     return S_OK;
981 }
982
983 static HRESULT WINAPI ConPt_Unadvise(
984         IConnectionPoint* This,
985         DWORD dwCookie)
986 {
987     ConPt *iface = (ConPt*)This;
988
989     if (dwCookie > iface->sinkCount)
990         return E_FAIL;
991     else
992     {
993         IUnknown_Release(iface->sink[dwCookie-1]);
994         iface->sink[dwCookie-1] = NULL;
995     }
996     return S_OK;
997 }
998
999 static HRESULT WINAPI ConPt_EnumConnections(
1000         IConnectionPoint* This,
1001         IEnumConnections **ppEnum)
1002 {
1003     EnumCon *ec;
1004
1005     ec = HeapAlloc(GetProcessHeap(),0,sizeof(EnumCon));
1006     ec->vtbl = &enum_vtbl;
1007     ec->refCount = 1;
1008     ec->pt = (ConPt*)This;
1009     ec->idx = 0;
1010     *ppEnum = (IEnumConnections*)ec;
1011
1012     return S_OK;
1013 }
1014
1015 static const IConnectionPointVtbl point_vtbl = {
1016     ConPt_QueryInterface,
1017     ConPt_AddRef,
1018     ConPt_Release,
1019
1020     ConPt_GetConnectionInterface,
1021     ConPt_GetConnectionPointContainer,
1022     ConPt_Advise,
1023     ConPt_Unadvise,
1024     ConPt_EnumConnections
1025 };
1026
1027 static HRESULT WINAPI EnumPt_QueryInterface(
1028         IEnumConnectionPoints* This,
1029         REFIID riid,
1030         void **ppvObject)
1031 {
1032     *ppvObject = NULL;
1033
1034     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumConnectionPoints))
1035     {
1036         *ppvObject = This;
1037     }
1038
1039     if (*ppvObject)
1040     {
1041         IUnknown_AddRef(This);
1042         return S_OK;
1043     }
1044
1045     trace("no interface\n");
1046     return E_NOINTERFACE;
1047 }
1048
1049 static ULONG WINAPI EnumPt_AddRef(IEnumConnectionPoints* This)
1050 {
1051     EnumPt *iface = (EnumPt*)This;
1052     return InterlockedIncrement(&iface->refCount);
1053 }
1054
1055 static ULONG WINAPI EnumPt_Release(IEnumConnectionPoints* This)
1056 {
1057     EnumPt *iface = (EnumPt*)This;
1058     ULONG ret;
1059
1060     ret = InterlockedDecrement(&iface->refCount);
1061     if (ret == 0)
1062         HeapFree(GetProcessHeap(),0,This);
1063     return ret;
1064 }
1065
1066 static HRESULT WINAPI EnumPt_Next(
1067         IEnumConnectionPoints* This,
1068         ULONG cConnections,
1069         IConnectionPoint **rgcd,
1070         ULONG *pcFetched)
1071 {
1072     EnumPt *iface = (EnumPt*)This;
1073
1074     if (cConnections > 0 && iface->idx < iface->container->ptCount)
1075     {
1076         *rgcd = iface->container->pt[iface->idx];
1077         IUnknown_AddRef(iface->container->pt[iface->idx]);
1078         if (pcFetched)
1079             *pcFetched = 1;
1080         iface->idx++;
1081         return S_OK;
1082     }
1083
1084     return E_FAIL;
1085 }
1086
1087 static HRESULT WINAPI EnumPt_Skip(
1088         IEnumConnectionPoints* This,
1089         ULONG cConnections)
1090 {
1091     return E_FAIL;
1092 }
1093
1094 static HRESULT WINAPI EnumPt_Reset(
1095         IEnumConnectionPoints* This)
1096 {
1097     return E_FAIL;
1098 }
1099
1100 static HRESULT WINAPI EnumPt_Clone(
1101         IEnumConnectionPoints* This,
1102         IEnumConnectionPoints **ppEnumPt)
1103 {
1104     return E_FAIL;
1105 }
1106
1107 static const IEnumConnectionPointsVtbl enumpt_vtbl = {
1108
1109     EnumPt_QueryInterface,
1110     EnumPt_AddRef,
1111     EnumPt_Release,
1112     EnumPt_Next,
1113     EnumPt_Skip,
1114     EnumPt_Reset,
1115     EnumPt_Clone
1116 };
1117
1118 static HRESULT WINAPI Contain_QueryInterface(
1119         IConnectionPointContainer* This,
1120         REFIID riid,
1121         void **ppvObject)
1122 {
1123     *ppvObject = NULL;
1124
1125     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IConnectionPointContainer))
1126     {
1127         *ppvObject = This;
1128     }
1129
1130     if (*ppvObject)
1131     {
1132         IUnknown_AddRef(This);
1133         return S_OK;
1134     }
1135
1136     trace("no interface\n");
1137     return E_NOINTERFACE;
1138 }
1139
1140 static ULONG WINAPI Contain_AddRef(
1141         IConnectionPointContainer* This)
1142 {
1143     Contain *iface = (Contain*)This;
1144     return InterlockedIncrement(&iface->refCount);
1145 }
1146
1147 static ULONG WINAPI Contain_Release(
1148         IConnectionPointContainer* This)
1149 {
1150     Contain *iface = (Contain*)This;
1151     ULONG ret;
1152
1153     ret = InterlockedDecrement(&iface->refCount);
1154     if (ret == 0)
1155     {
1156         if (iface->ptCount > 0)
1157         {
1158             int i;
1159             for (i = 0; i < iface->ptCount; i++)
1160                 IUnknown_Release(iface->pt[i]);
1161             HeapFree(GetProcessHeap(),0,iface->pt);
1162         }
1163         HeapFree(GetProcessHeap(),0,This);
1164     }
1165     return ret;
1166 }
1167
1168 static HRESULT WINAPI Contain_EnumConnectionPoints(
1169         IConnectionPointContainer* This,
1170         IEnumConnectionPoints **ppEnum)
1171 {
1172     EnumPt *ec;
1173
1174     ec = HeapAlloc(GetProcessHeap(),0,sizeof(EnumPt));
1175     ec->vtbl = &enumpt_vtbl;
1176     ec->refCount = 1;
1177     ec->idx= 0;
1178     ec->container = (Contain*)This;
1179     *ppEnum = (IEnumConnectionPoints*)ec;
1180
1181     return S_OK;
1182 }
1183
1184 static HRESULT WINAPI Contain_FindConnectionPoint(
1185         IConnectionPointContainer* This,
1186         REFIID riid,
1187         IConnectionPoint **ppCP)
1188 {
1189     Contain *iface = (Contain*)This;
1190     ConPt *pt;
1191
1192     if (!IsEqualIID(riid, &IID_NULL) || iface->ptCount ==0)
1193     {
1194         pt = HeapAlloc(GetProcessHeap(),0,sizeof(ConPt));
1195         pt->vtbl = &point_vtbl;
1196         pt->refCount = 1;
1197         pt->sinkCount = 0;
1198         pt->sink = NULL;
1199         pt->container = iface;
1200         pt->id = IID_IDispatch;
1201
1202         if (iface->ptCount == 0)
1203             iface->pt =HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown*));
1204         else
1205             iface->pt = HeapReAlloc(GetProcessHeap(),0,iface->pt,sizeof(IUnknown*)*(iface->ptCount+1));
1206         iface->pt[iface->ptCount] = (IConnectionPoint*)pt;
1207         iface->ptCount++;
1208
1209         *ppCP = (IConnectionPoint*)pt;
1210     }
1211     else
1212     {
1213         *ppCP = iface->pt[0];
1214         IUnknown_AddRef((IUnknown*)*ppCP);
1215     }
1216
1217     return S_OK;
1218 }
1219
1220 static const IConnectionPointContainerVtbl contain_vtbl = {
1221     Contain_QueryInterface,
1222     Contain_AddRef,
1223     Contain_Release,
1224
1225     Contain_EnumConnectionPoints,
1226     Contain_FindConnectionPoint
1227 };
1228
1229 static void test_IConnectionPoint(void)
1230 {
1231     HRESULT rc;
1232     ULONG ref;
1233     IConnectionPoint *point;
1234     Contain *container;
1235     Disp *dispatch;
1236     DWORD cookie = 0xffffffff;
1237     DISPPARAMS params;
1238     VARIANT vars[10];
1239
1240     if (!pIConnectionPoint_SimpleInvoke || !pConnectToConnectionPoint)
1241     {
1242         win_skip("IConnectionPoint Apis not present\n");
1243         return;
1244     }
1245
1246     container = HeapAlloc(GetProcessHeap(),0,sizeof(Contain));
1247     container->vtbl = &contain_vtbl;
1248     container->refCount = 1;
1249     container->ptCount = 0;
1250     container->pt = NULL;
1251
1252     dispatch = HeapAlloc(GetProcessHeap(),0,sizeof(Disp));
1253     dispatch->vtbl = &disp_vtbl;
1254     dispatch->refCount = 1;
1255
1256     rc = pConnectToConnectionPoint((IUnknown*)dispatch, &IID_NULL, TRUE, (IUnknown*)container, &cookie, &point);
1257     ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1258     ok(point != NULL, "returned ConnectionPoint is NULL\n");
1259     ok(cookie != 0xffffffff, "invalid cookie returned\n");
1260
1261     rc = pIConnectionPoint_SimpleInvoke(point,0xa0,NULL);
1262     ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1263
1264     if (pSHPackDispParams)
1265     {
1266         memset(&params, 0xc0, sizeof(params));
1267         memset(vars, 0xc0, sizeof(vars));
1268         rc = pSHPackDispParams(&params, vars, 2, VT_I4, 0xdeadbeef, VT_BSTR, 0xdeadcafe);
1269         ok(rc == S_OK, "SHPackDispParams failed: %08x\n", rc);
1270
1271         rc = pIConnectionPoint_SimpleInvoke(point,0xa1,&params);
1272         ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1273     }
1274     else
1275         win_skip("pSHPackDispParams not present\n");
1276
1277     rc = pConnectToConnectionPoint(NULL, &IID_NULL, FALSE, (IUnknown*)container, &cookie, NULL);
1278     ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1279
1280 /* MSDN says this should be required but it crashs on XP
1281     IUnknown_Release(point);
1282 */
1283     ref = IUnknown_Release((IUnknown*)container);
1284     ok(ref == 0, "leftover IConnectionPointContainer reference %i\n",ref);
1285     ref = IUnknown_Release((IUnknown*)dispatch);
1286     ok(ref == 0, "leftover IDispatch reference %i\n",ref);
1287 }
1288
1289 typedef struct _propbag
1290 {
1291     const IPropertyBagVtbl *vtbl;
1292     LONG   refCount;
1293
1294 } PropBag;
1295
1296
1297 static HRESULT WINAPI Prop_QueryInterface(
1298         IPropertyBag* This,
1299         REFIID riid,
1300         void **ppvObject)
1301 {
1302     *ppvObject = NULL;
1303
1304     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPropertyBag))
1305     {
1306         *ppvObject = This;
1307     }
1308
1309     if (*ppvObject)
1310     {
1311         IUnknown_AddRef(This);
1312         return S_OK;
1313     }
1314
1315     trace("no interface\n");
1316     return E_NOINTERFACE;
1317 }
1318
1319 static ULONG WINAPI Prop_AddRef(
1320         IPropertyBag* This)
1321 {
1322     PropBag *iface = (PropBag*)This;
1323     return InterlockedIncrement(&iface->refCount);
1324 }
1325
1326 static ULONG WINAPI Prop_Release(
1327         IPropertyBag* This)
1328 {
1329     PropBag *iface = (PropBag*)This;
1330     ULONG ret;
1331
1332     ret = InterlockedDecrement(&iface->refCount);
1333     if (ret == 0)
1334         HeapFree(GetProcessHeap(),0,This);
1335     return ret;
1336 }
1337
1338 static HRESULT WINAPI Prop_Read(
1339         IPropertyBag* This,
1340         LPCOLESTR pszPropName,
1341         VARIANT *pVar,
1342         IErrorLog *pErrorLog)
1343 {
1344     V_VT(pVar) = VT_BLOB|VT_BYREF;
1345     V_BYREF(pVar) = (LPVOID)0xdeadcafe;
1346     return S_OK;
1347 }
1348
1349 static HRESULT WINAPI Prop_Write(
1350         IPropertyBag* This,
1351         LPCOLESTR pszPropName,
1352         VARIANT *pVar)
1353 {
1354     return S_OK;
1355 }
1356
1357
1358 static const IPropertyBagVtbl prop_vtbl = {
1359     Prop_QueryInterface,
1360     Prop_AddRef,
1361     Prop_Release,
1362
1363     Prop_Read,
1364     Prop_Write
1365 };
1366
1367 static void test_SHPropertyBag_ReadLONG(void)
1368 {
1369     PropBag *pb;
1370     HRESULT rc;
1371     LONG out;
1372     static const WCHAR szName1[] = {'n','a','m','e','1',0};
1373
1374     if (!pSHPropertyBag_ReadLONG)
1375     {
1376         win_skip("SHPropertyBag_ReadLONG not present\n");
1377         return;
1378     }
1379
1380     pb = HeapAlloc(GetProcessHeap(),0,sizeof(PropBag));
1381     pb->refCount = 1;
1382     pb->vtbl = &prop_vtbl;
1383
1384     out = 0xfeedface;
1385     rc = pSHPropertyBag_ReadLONG(NULL, szName1, &out);
1386     ok(rc == E_INVALIDARG || broken(rc == 0), "incorrect return %x\n",rc);
1387     ok(out == 0xfeedface, "value should not have changed\n");
1388     rc = pSHPropertyBag_ReadLONG((IPropertyBag*)pb, NULL, &out);
1389     ok(rc == E_INVALIDARG || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
1390     ok(out == 0xfeedface, "value should not have changed\n");
1391     rc = pSHPropertyBag_ReadLONG((IPropertyBag*)pb, szName1, NULL);
1392     ok(rc == E_INVALIDARG || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
1393     ok(out == 0xfeedface, "value should not have changed\n");
1394     rc = pSHPropertyBag_ReadLONG((IPropertyBag*)pb, szName1, &out);
1395     ok(rc == DISP_E_BADVARTYPE || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
1396     ok(out == 0xfeedface  || broken(out == 0xfeedfa00), "value should not have changed %x\n",out);
1397     IUnknown_Release((IUnknown*)pb);
1398 }
1399
1400 START_TEST(ordinal)
1401 {
1402   hShlwapi = GetModuleHandleA("shlwapi.dll");
1403
1404   pGetAcceptLanguagesA = (void*)GetProcAddress(hShlwapi, (LPSTR)14);
1405   pSHSearchMapInt = (void*)GetProcAddress(hShlwapi, (LPSTR)198);
1406   pSHAllocShared=(void*)GetProcAddress(hShlwapi,(char*)7);
1407   pSHLockShared=(void*)GetProcAddress(hShlwapi,(char*)8);
1408   pSHUnlockShared=(void*)GetProcAddress(hShlwapi,(char*)9);
1409   pSHFreeShared=(void*)GetProcAddress(hShlwapi,(char*)10);
1410   pSHPackDispParams=(void*)GetProcAddress(hShlwapi,(char*)282);
1411   pIConnectionPoint_SimpleInvoke=(void*)GetProcAddress(hShlwapi,(char*)284);
1412   pIConnectionPoint_InvokeWithCancel=(void*)GetProcAddress(hShlwapi,(char*)283);
1413   pConnectToConnectionPoint=(void*)GetProcAddress(hShlwapi,(char*)168);
1414   pSHPropertyBag_ReadLONG=(void*)GetProcAddress(hShlwapi,(char*)496);
1415
1416   hmlang = LoadLibraryA("mlang.dll");
1417   pLcidToRfc1766A = (void *)GetProcAddress(hmlang, "LcidToRfc1766A");
1418
1419   test_GetAcceptLanguagesA();
1420   test_SHSearchMapInt();
1421   test_alloc_shared();
1422   test_fdsa();
1423   test_GetShellSecurityDescriptor();
1424   test_SHPackDispParams();
1425   test_IConnectionPoint();
1426   test_SHPropertyBag_ReadLONG();
1427 }