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