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