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 suceed
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(¶ms, 0xc0, sizeof(params));
715 memset(vars, 0xc0, sizeof(vars));
716 hres = pSHPackDispParams(¶ms, 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(¶ms, 0xc0, sizeof(params));
726 hres = pSHPackDispParams(¶ms, 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(¶ms, 0xc0, sizeof(params));
735 hres = pSHPackDispParams(¶ms, 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 IUnknown_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 IUnknown_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 IUnknown_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 IUnknown_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 IUnknown_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 IUnknown_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 IUnknown_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(¶ms, 0xc0, sizeof(params));
1410 memset(vars, 0xc0, sizeof(vars));
1411 rc = pSHPackDispParams(¶ms, 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,¶ms);
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 IUnknown_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 ok(out == 0xfeedface, "value should not have changed\n");
1542 rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, szName1, &out);
1543 ok(rc == DISP_E_BADVARTYPE || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
1544 ok(out == 0xfeedface || broken(out == 0xfeedfa00), "value should not have changed %x\n",out);
1545 IUnknown_Release((IUnknown*)pb);
1546 }
1547
1548
1549
1550 static void test_SHSetWindowBits(void)
1551 {
1552 HWND hwnd;
1553 DWORD style, styleold;
1554 WNDCLASSA clsA;
1555
1556 if(!pSHSetWindowBits)
1557 {
1558 win_skip("SHSetWindowBits is not available\n");
1559 return;
1560 }
1561
1562 clsA.style = 0;
1563 clsA.lpfnWndProc = DefWindowProcA;
1564 clsA.cbClsExtra = 0;
1565 clsA.cbWndExtra = 0;
1566 clsA.hInstance = GetModuleHandleA(NULL);
1567 clsA.hIcon = 0;
1568 clsA.hCursor = LoadCursorA(0, IDC_ARROW);
1569 clsA.hbrBackground = NULL;
1570 clsA.lpszMenuName = NULL;
1571 clsA.lpszClassName = "Shlwapi test class";
1572 RegisterClassA(&clsA);
1573
1574 hwnd = CreateWindowA("Shlwapi test class", "Test", WS_VISIBLE, 0, 0, 100, 100,
1575 NULL, NULL, GetModuleHandle(NULL), 0);
1576 ok(IsWindow(hwnd), "failed to create window\n");
1577
1578 /* null window */
1579 SetLastError(0xdeadbeef);
1580 style = pSHSetWindowBits(NULL, GWL_STYLE, 0, 0);
1581 ok(style == 0, "expected 0 retval, got %d\n", style);
1582 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
1583 broken(GetLastError() == 0xdeadbeef), /* Win9x/WinMe */
1584 "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
1585
1586 /* zero mask, zero flags */
1587 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1588 style = pSHSetWindowBits(hwnd, GWL_STYLE, 0, 0);
1589 ok(styleold == style, "expected old style\n");
1590 ok(styleold == GetWindowLongA(hwnd, GWL_STYLE), "expected to keep old style\n");
1591
1592 /* test mask */
1593 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1594 ok(styleold & WS_VISIBLE, "expected WS_VISIBLE\n");
1595 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1596
1597 ok(style == styleold, "expected previous style, got %x\n", style);
1598 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1599
1600 /* test mask, unset style bit used */
1601 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1602 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1603 ok(style == styleold, "expected previous style, got %x\n", style);
1604 ok(styleold == GetWindowLongA(hwnd, GWL_STYLE), "expected to keep old style\n");
1605
1606 /* set back with flags */
1607 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1608 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, WS_VISIBLE);
1609 ok(style == styleold, "expected previous style, got %x\n", style);
1610 ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "expected updated style\n");
1611
1612 /* reset and try to set without a mask */
1613 pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1614 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1615 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1616 style = pSHSetWindowBits(hwnd, GWL_STYLE, 0, WS_VISIBLE);
1617 ok(style == styleold, "expected previous style, got %x\n", style);
1618 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1619
1620 DestroyWindow(hwnd);
1621
1622 UnregisterClassA("Shlwapi test class", GetModuleHandleA(NULL));
1623 }
1624
1625 static void test_SHFormatDateTimeA(void)
1626 {
1627 FILETIME UNALIGNED filetime;
1628 CHAR buff[100], buff2[100], buff3[100];
1629 SYSTEMTIME st;
1630 DWORD flags;
1631 INT ret;
1632
1633 if(!pSHFormatDateTimeA)
1634 {
1635 win_skip("pSHFormatDateTimeA isn't available\n");
1636 return;
1637 }
1638
1639 if (0)
1640 {
1641 /* crashes on native */
1642 pSHFormatDateTimeA(NULL, NULL, NULL, 0);
1643 }
1644
1645 GetLocalTime(&st);
1646 SystemTimeToFileTime(&st, &filetime);
1647 /* SHFormatDateTime expects input as utc */
1648 LocalFileTimeToFileTime(&filetime, &filetime);
1649
1650 /* no way to get required buffer length here */
1651 SetLastError(0xdeadbeef);
1652 ret = pSHFormatDateTimeA(&filetime, NULL, NULL, 0);
1653 ok(ret == 0, "got %d\n", ret);
1654 ok(GetLastError() == 0xdeadbeef || broken(GetLastError() == ERROR_SUCCESS /* Win7 */),
1655 "expected 0xdeadbeef, got %d\n", GetLastError());
1656
1657 SetLastError(0xdeadbeef);
1658 buff[0] = 'a'; buff[1] = 0;
1659 ret = pSHFormatDateTimeA(&filetime, NULL, buff, 0);
1660 ok(ret == 0, "got %d\n", ret);
1661 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1662 ok(buff[0] == 'a', "expected same string, got %s\n", buff);
1663
1664 /* flags needs to have FDTF_NOAUTOREADINGORDER for these tests to succeed on Vista+ */
1665
1666 /* all combinations documented as invalid succeeded */
1667 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTTIME | FDTF_LONGTIME;
1668 SetLastError(0xdeadbeef);
1669 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1670 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1671 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1672
1673 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_LONGDATE;
1674 SetLastError(0xdeadbeef);
1675 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1676 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1677 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1678
1679 flags = FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE;
1680 SetLastError(0xdeadbeef);
1681 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1682 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1683 ok(GetLastError() == 0xdeadbeef ||
1684 broken(GetLastError() == ERROR_INVALID_FLAGS), /* Win9x/WinMe */
1685 "expected 0xdeadbeef, got %d\n", GetLastError());
1686
1687 /* now check returned strings */
1688 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTTIME;
1689 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1690 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1691 ret = GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff2, sizeof(buff2));
1692 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1693 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1694
1695 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGTIME;
1696 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1697 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1698 ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2));
1699 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1700 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1701
1702 /* both time flags */
1703 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGTIME | FDTF_SHORTTIME;
1704 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1705 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1706 ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2));
1707 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1708 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1709
1710 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE;
1711 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1712 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1713 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1714 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1715 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1716
1717 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE;
1718 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1719 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1720 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1721 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1722 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1723
1724 /* both date flags */
1725 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_SHORTDATE;
1726 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1727 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1728 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1729 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1730 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1731
1732 /* various combinations of date/time flags */
1733 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_SHORTTIME;
1734 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1735 ok(ret == lstrlenA(buff)+1, "got %d, length %d\n", ret, lstrlenA(buff)+1);
1736 ret = GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3));
1737 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1738 ok(lstrcmpA(buff3, buff + lstrlenA(buff) - lstrlenA(buff3)) == 0,
1739 "expected (%s), got (%s) for time part\n",
1740 buff3, buff + lstrlenA(buff) - lstrlenA(buff3));
1741 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1742 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1743 buff[lstrlenA(buff2)] = '\0';
1744 ok(lstrcmpA(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1745 buff2, buff);
1746
1747 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_LONGTIME;
1748 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1749 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1750 ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3));
1751 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1752 ok(lstrcmpA(buff3, buff + lstrlenA(buff) - lstrlenA(buff3)) == 0,
1753 "expected (%s), got (%s) for time part\n",
1754 buff3, buff + lstrlenA(buff) - lstrlenA(buff3));
1755 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1756 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1757 buff[lstrlenA(buff2)] = '\0';
1758 ok(lstrcmpA(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1759 buff2, buff);
1760
1761 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_SHORTTIME;
1762 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1763 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1764 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1765 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1766 strcat(buff2, " ");
1767 ret = GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3));
1768 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1769 strcat(buff2, buff3);
1770 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1771
1772 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_LONGTIME;
1773 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1774 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1775 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1776 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1777 strcat(buff2, " ");
1778 ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3));
1779 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1780 strcat(buff2, buff3);
1781 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1782 }
1783
1784 static void test_SHFormatDateTimeW(void)
1785 {
1786 FILETIME UNALIGNED filetime;
1787 WCHAR buff[100], buff2[100], buff3[100], *p1, *p2;
1788 SYSTEMTIME st;
1789 DWORD flags;
1790 INT ret;
1791 static const WCHAR spaceW[] = {' ',0};
1792 #define UNICODE_LTR_MARK 0x200e
1793
1794 if(!pSHFormatDateTimeW)
1795 {
1796 win_skip("pSHFormatDateTimeW isn't available\n");
1797 return;
1798 }
1799
1800 if (0)
1801 {
1802 /* crashes on native */
1803 pSHFormatDateTimeW(NULL, NULL, NULL, 0);
1804 }
1805
1806 GetLocalTime(&st);
1807 SystemTimeToFileTime(&st, &filetime);
1808 /* SHFormatDateTime expects input as utc */
1809 LocalFileTimeToFileTime(&filetime, &filetime);
1810
1811 /* no way to get required buffer length here */
1812 SetLastError(0xdeadbeef);
1813 ret = pSHFormatDateTimeW(&filetime, NULL, NULL, 0);
1814 ok(ret == 0, "expected 0, got %d\n", ret);
1815 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1816
1817 SetLastError(0xdeadbeef);
1818 buff[0] = 'a'; buff[1] = 0;
1819 ret = pSHFormatDateTimeW(&filetime, NULL, buff, 0);
1820 ok(ret == 0, "expected 0, got %d\n", ret);
1821 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1822 ok(buff[0] == 'a', "expected same string\n");
1823
1824 /* all combinations documented as invalid succeeded */
1825 flags = FDTF_SHORTTIME | FDTF_LONGTIME;
1826 SetLastError(0xdeadbeef);
1827 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1828 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1829 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1830 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1831
1832 flags = FDTF_SHORTDATE | FDTF_LONGDATE;
1833 SetLastError(0xdeadbeef);
1834 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1835 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1836 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1837 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1838
1839 flags = FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE;
1840 SetLastError(0xdeadbeef);
1841 buff[0] = 0; /* NT4 doesn't clear the buffer on failure */
1842 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1843 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1844 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1845 ok(GetLastError() == 0xdeadbeef ||
1846 broken(GetLastError() == ERROR_INVALID_FLAGS), /* Win9x/WinMe/NT4 */
1847 "expected 0xdeadbeef, got %d\n", GetLastError());
1848
1849 /* now check returned strings */
1850 flags = FDTF_SHORTTIME;
1851 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1852 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1853 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1854 SetLastError(0xdeadbeef);
1855 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1856 if (ret == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1857 {
1858 win_skip("Needed W-functions are not implemented\n");
1859 return;
1860 }
1861 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1862 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1863
1864 flags = FDTF_LONGTIME;
1865 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1866 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1867 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1868 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1869 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1870 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1871
1872 /* both time flags */
1873 flags = FDTF_LONGTIME | FDTF_SHORTTIME;
1874 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1875 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1876 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1877 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1878 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1879 ok(lstrcmpW(buff, buff2) == 0, "expected equal string\n");
1880
1881 flags = FDTF_SHORTDATE;
1882 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1883 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1884 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1885 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1886 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1887 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1888
1889 flags = FDTF_LONGDATE;
1890 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1891 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1892 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1893 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1894 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1895 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1896
1897 /* both date flags */
1898 flags = FDTF_LONGDATE | FDTF_SHORTDATE;
1899 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1900 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1901 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1902 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1903 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1904 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1905
1906 /* various combinations of date/time flags */
1907 flags = FDTF_LONGDATE | FDTF_SHORTTIME;
1908 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1909 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1910 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1911 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1912 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1913 ok(lstrcmpW(buff3, buff + lstrlenW(buff) - lstrlenW(buff3)) == 0,
1914 "expected (%s), got (%s) for time part\n",
1915 wine_dbgstr_w(buff3), wine_dbgstr_w(buff + lstrlenW(buff) - lstrlenW(buff3)));
1916 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1917 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1918 p1 = buff;
1919 p2 = buff2;
1920 while (*p2 != '\0')
1921 {
1922 while (*p1 == UNICODE_LTR_MARK)
1923 p1++;
1924 while (*p2 == UNICODE_LTR_MARK)
1925 p2++;
1926 p1++;
1927 p2++;
1928 }
1929 *p1 = '\0';
1930 ok(lstrcmpW(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1931 wine_dbgstr_w(buff2), wine_dbgstr_w(buff));
1932
1933 flags = FDTF_LONGDATE | FDTF_LONGTIME;
1934 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1935 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1936 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1937 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1938 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1939 ok(lstrcmpW(buff3, buff + lstrlenW(buff) - lstrlenW(buff3)) == 0,
1940 "expected (%s), got (%s) for time part\n",
1941 wine_dbgstr_w(buff3), wine_dbgstr_w(buff + lstrlenW(buff) - lstrlenW(buff3)));
1942 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1943 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1944 p1 = buff;
1945 p2 = buff2;
1946 while (*p2 != '\0')
1947 {
1948 while (*p1 == UNICODE_LTR_MARK)
1949 p1++;
1950 while (*p2 == UNICODE_LTR_MARK)
1951 p2++;
1952 p1++;
1953 p2++;
1954 }
1955 *p1 = '\0';
1956 ok(lstrcmpW(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1957 wine_dbgstr_w(buff2), wine_dbgstr_w(buff));
1958
1959 flags = FDTF_SHORTDATE | FDTF_SHORTTIME;
1960 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1961 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1962 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1963 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1964 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1965 lstrcatW(buff2, spaceW);
1966 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1967 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1968 lstrcatW(buff2, buff3);
1969 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1970
1971 flags = FDTF_SHORTDATE | FDTF_LONGTIME;
1972 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1973 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1974 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1975 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1976 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1977 lstrcatW(buff2, spaceW);
1978 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1979 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1980 lstrcatW(buff2, buff3);
1981 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1982 }
1983
1984 static void test_SHGetObjectCompatFlags(void)
1985 {
1986 struct compat_value {
1987 CHAR nameA[30];
1988 DWORD value;
1989 };
1990
1991 struct compat_value values[] = {
1992 { "OTNEEDSSFCACHE", 0x1 },
1993 { "NO_WEBVIEW", 0x2 },
1994 { "UNBINDABLE", 0x4 },
1995 { "PINDLL", 0x8 },
1996 { "NEEDSFILESYSANCESTOR", 0x10 },
1997 { "NOTAFILESYSTEM", 0x20 },
1998 { "CTXMENU_NOVERBS", 0x40 },
1999 { "CTXMENU_LIMITEDQI", 0x80 },
2000 { "COCREATESHELLFOLDERONLY", 0x100 },
2001 { "NEEDSSTORAGEANCESTOR", 0x200 },
2002 { "NOLEGACYWEBVIEW", 0x400 },
2003 { "CTXMENU_XPQCMFLAGS", 0x1000 },
2004 { "NOIPROPERTYSTORE", 0x2000 }
2005 };
2006
2007 static const char compat_path[] = "Software\\Microsoft\\Windows\\CurrentVersion\\ShellCompatibility\\Objects";
2008 void *pColorAdjustLuma = GetProcAddress(hShlwapi, "ColorAdjustLuma");
2009 CHAR keyA[39]; /* {CLSID} */
2010 HKEY root;
2011 DWORD ret;
2012 int i;
2013
2014 if (!pSHGetObjectCompatFlags)
2015 {
2016 win_skip("SHGetObjectCompatFlags isn't available\n");
2017 return;
2018 }
2019
2020 if (pColorAdjustLuma && pColorAdjustLuma == pSHGetObjectCompatFlags) /* win2k */
2021 {
2022 win_skip("Skipping SHGetObjectCompatFlags, same ordinal used for ColorAdjustLuma\n");
2023 return;
2024 }
2025
2026 /* null args */
2027 ret = pSHGetObjectCompatFlags(NULL, NULL);
2028 ok(ret == 0, "got %d\n", ret);
2029
2030 ret = RegOpenKeyA(HKEY_LOCAL_MACHINE, compat_path, &root);
2031 if (ret != ERROR_SUCCESS)
2032 {
2033 skip("No compatibility class data found\n");
2034 return;
2035 }
2036
2037 for (i = 0; RegEnumKeyA(root, i, keyA, sizeof(keyA)) == ERROR_SUCCESS; i++)
2038 {
2039 HKEY clsid_key;
2040
2041 if (RegOpenKeyA(root, keyA, &clsid_key) == ERROR_SUCCESS)
2042 {
2043 CHAR valueA[30];
2044 DWORD expected = 0, got, length = sizeof(valueA);
2045 CLSID clsid;
2046 int v;
2047
2048 for (v = 0; RegEnumValueA(clsid_key, v, valueA, &length, NULL, NULL, NULL, NULL) == ERROR_SUCCESS; v++)
2049 {
2050 int j;
2051
2052 for (j = 0; j < sizeof(values)/sizeof(struct compat_value); j++)
2053 if (lstrcmpA(values[j].nameA, valueA) == 0)
2054 {
2055 expected |= values[j].value;
2056 break;
2057 }
2058
2059 length = sizeof(valueA);
2060 }
2061
2062 pGUIDFromStringA(keyA, &clsid);
2063 got = pSHGetObjectCompatFlags(NULL, &clsid);
2064 ok(got == expected, "got 0x%08x, expected 0x%08x. Key %s\n", got, expected, keyA);
2065
2066 RegCloseKey(clsid_key);
2067 }
2068 }
2069
2070 RegCloseKey(root);
2071 }
2072
2073 typedef struct {
2074 IOleCommandTarget IOleCommandTarget_iface;
2075 LONG ref;
2076 } IOleCommandTargetImpl;
2077
2078 static inline IOleCommandTargetImpl *impl_from_IOleCommandTarget(IOleCommandTarget *iface)
2079 {
2080 return CONTAINING_RECORD(iface, IOleCommandTargetImpl, IOleCommandTarget_iface);
2081 }
2082
2083 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl;
2084
2085 static IOleCommandTarget* IOleCommandTargetImpl_Construct(void)
2086 {
2087 IOleCommandTargetImpl *obj;
2088
2089 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2090 obj->IOleCommandTarget_iface.lpVtbl = &IOleCommandTargetImpl_Vtbl;
2091 obj->ref = 1;
2092
2093 return &obj->IOleCommandTarget_iface;
2094 }
2095
2096 static HRESULT WINAPI IOleCommandTargetImpl_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppvObj)
2097 {
2098 IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface);
2099
2100 if (IsEqualIID(riid, &IID_IUnknown) ||
2101 IsEqualIID(riid, &IID_IOleCommandTarget))
2102 {
2103 *ppvObj = This;
2104 }
2105
2106 if(*ppvObj)
2107 {
2108 IUnknown_AddRef(iface);
2109 return S_OK;
2110 }
2111
2112 return E_NOINTERFACE;
2113 }
2114
2115 static ULONG WINAPI IOleCommandTargetImpl_AddRef(IOleCommandTarget *iface)
2116 {
2117 IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface);
2118 return InterlockedIncrement(&This->ref);
2119 }
2120
2121 static ULONG WINAPI IOleCommandTargetImpl_Release(IOleCommandTarget *iface)
2122 {
2123 IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface);
2124 ULONG ref = InterlockedDecrement(&This->ref);
2125
2126 if (!ref)
2127 {
2128 HeapFree(GetProcessHeap(), 0, This);
2129 return 0;
2130 }
2131 return ref;
2132 }
2133
2134 static HRESULT WINAPI IOleCommandTargetImpl_QueryStatus(
2135 IOleCommandTarget *iface, const GUID *group, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText)
2136 {
2137 return E_NOTIMPL;
2138 }
2139
2140 static HRESULT WINAPI IOleCommandTargetImpl_Exec(
2141 IOleCommandTarget *iface,
2142 const GUID *CmdGroup,
2143 DWORD nCmdID,
2144 DWORD nCmdexecopt,
2145 VARIANT *pvaIn,
2146 VARIANT *pvaOut)
2147 {
2148 add_call(&trace_got, 3, CmdGroup, (void*)(DWORD_PTR)nCmdID, (void*)(DWORD_PTR)nCmdexecopt, pvaIn, pvaOut);
2149 return S_OK;
2150 }
2151
2152 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl =
2153 {
2154 IOleCommandTargetImpl_QueryInterface,
2155 IOleCommandTargetImpl_AddRef,
2156 IOleCommandTargetImpl_Release,
2157 IOleCommandTargetImpl_QueryStatus,
2158 IOleCommandTargetImpl_Exec
2159 };
2160
2161 typedef struct {
2162 IServiceProvider IServiceProvider_iface;
2163 LONG ref;
2164 } IServiceProviderImpl;
2165
2166 static inline IServiceProviderImpl *impl_from_IServiceProvider(IServiceProvider *iface)
2167 {
2168 return CONTAINING_RECORD(iface, IServiceProviderImpl, IServiceProvider_iface);
2169 }
2170
2171 typedef struct {
2172 IProfferService IProfferService_iface;
2173 LONG ref;
2174 } IProfferServiceImpl;
2175
2176 static inline IProfferServiceImpl *impl_from_IProfferService(IProfferService *iface)
2177 {
2178 return CONTAINING_RECORD(iface, IProfferServiceImpl, IProfferService_iface);
2179 }
2180
2181
2182 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl;
2183 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl;
2184
2185 static IServiceProvider* IServiceProviderImpl_Construct(void)
2186 {
2187 IServiceProviderImpl *obj;
2188
2189 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2190 obj->IServiceProvider_iface.lpVtbl = &IServiceProviderImpl_Vtbl;
2191 obj->ref = 1;
2192
2193 return &obj->IServiceProvider_iface;
2194 }
2195
2196 static IProfferService* IProfferServiceImpl_Construct(void)
2197 {
2198 IProfferServiceImpl *obj;
2199
2200 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2201 obj->IProfferService_iface.lpVtbl = &IProfferServiceImpl_Vtbl;
2202 obj->ref = 1;
2203
2204 return &obj->IProfferService_iface;
2205 }
2206
2207 static HRESULT WINAPI IServiceProviderImpl_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppvObj)
2208 {
2209 IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
2210
2211 if (IsEqualIID(riid, &IID_IUnknown) ||
2212 IsEqualIID(riid, &IID_IServiceProvider))
2213 {
2214 *ppvObj = This;
2215 }
2216
2217 if(*ppvObj)
2218 {
2219 IUnknown_AddRef(iface);
2220 /* native uses redefined IID_IServiceProvider symbol, so we can't compare pointers */
2221 if (IsEqualIID(riid, &IID_IServiceProvider))
2222 add_call(&trace_got, 1, iface, &IID_IServiceProvider, 0, 0, 0);
2223 return S_OK;
2224 }
2225
2226 return E_NOINTERFACE;
2227 }
2228
2229 static ULONG WINAPI IServiceProviderImpl_AddRef(IServiceProvider *iface)
2230 {
2231 IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
2232 return InterlockedIncrement(&This->ref);
2233 }
2234
2235 static ULONG WINAPI IServiceProviderImpl_Release(IServiceProvider *iface)
2236 {
2237 IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
2238 ULONG ref = InterlockedDecrement(&This->ref);
2239
2240 if (!ref)
2241 {
2242 HeapFree(GetProcessHeap(), 0, This);
2243 return 0;
2244 }
2245 return ref;
2246 }
2247
2248 static HRESULT WINAPI IServiceProviderImpl_QueryService(
2249 IServiceProvider *iface, REFGUID service, REFIID riid, void **ppv)
2250 {
2251 /* native uses redefined pointer for IID_IOleCommandTarget, not one from uuid.lib */
2252 if (IsEqualIID(riid, &IID_IOleCommandTarget))
2253 {
2254 add_call(&trace_got, 2, iface, service, &IID_IOleCommandTarget, 0, 0);
2255 *ppv = IOleCommandTargetImpl_Construct();
2256 }
2257 if (IsEqualIID(riid, &IID_IProfferService))
2258 {
2259 if (IsEqualIID(service, &IID_IProfferService))
2260 add_call(&trace_got, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2261 *ppv = IProfferServiceImpl_Construct();
2262 }
2263 return S_OK;
2264 }
2265
2266 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl =
2267 {
2268 IServiceProviderImpl_QueryInterface,
2269 IServiceProviderImpl_AddRef,
2270 IServiceProviderImpl_Release,
2271 IServiceProviderImpl_QueryService
2272 };
2273
2274 static void test_IUnknown_QueryServiceExec(void)
2275 {
2276 IServiceProvider *provider = IServiceProviderImpl_Construct();
2277 static const GUID dummy_serviceid = { 0xdeadbeef };
2278 static const GUID dummy_groupid = { 0xbeefbeef };
2279 call_trace_t trace_expected;
2280 HRESULT hr;
2281
2282 /* on <=W2K platforms same ordinal used for another export with different
2283 prototype, so skipping using this indirect condition */
2284 if (is_win2k_and_lower)
2285 {
2286 win_skip("IUnknown_QueryServiceExec is not available\n");
2287 return;
2288 }
2289
2290 /* null source pointer */
2291 hr = pIUnknown_QueryServiceExec(NULL, &dummy_serviceid, &dummy_groupid, 0, 0, 0, 0);
2292 ok(hr == E_FAIL, "got 0x%08x\n", hr);
2293
2294 /* expected trace:
2295 IUnknown_QueryServiceExec( ptr1, serviceid, groupid, arg1, arg2, arg3, arg4);
2296 -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &prov );
2297 -> IServiceProvider_QueryService( prov, serviceid, &IID_IOleCommandTarget, &obj );
2298 -> IOleCommandTarget_Exec( obj, groupid, arg1, arg2, arg3, arg4 );
2299 */
2300 init_call_trace(&trace_expected);
2301
2302 add_call(&trace_expected, 1, provider, &IID_IServiceProvider, 0, 0, 0);
2303 add_call(&trace_expected, 2, provider, &dummy_serviceid, &IID_IOleCommandTarget, 0, 0);
2304 add_call(&trace_expected, 3, &dummy_groupid, (void*)0x1, (void*)0x2, (void*)0x3, (void*)0x4);
2305
2306 init_call_trace(&trace_got);
2307 hr = pIUnknown_QueryServiceExec((IUnknown*)provider, &dummy_serviceid, &dummy_groupid, 0x1, 0x2, (void*)0x3, (void*)0x4);
2308 ok(hr == S_OK, "got 0x%08x\n", hr);
2309
2310 ok_trace(&trace_expected, &trace_got);
2311
2312 free_call_trace(&trace_expected);
2313 free_call_trace(&trace_got);
2314
2315 IServiceProvider_Release(provider);
2316 }
2317
2318
2319 static HRESULT WINAPI IProfferServiceImpl_QueryInterface(IProfferService *iface, REFIID riid, void **ppvObj)
2320 {
2321 IProfferServiceImpl *This = impl_from_IProfferService(iface);
2322
2323 if (IsEqualIID(riid, &IID_IUnknown) ||
2324 IsEqualIID(riid, &IID_IProfferService))
2325 {
2326 *ppvObj = This;
2327 }
2328 else if (IsEqualIID(riid, &IID_IServiceProvider))
2329 {
2330 *ppvObj = IServiceProviderImpl_Construct();
2331 add_call(&trace_got, 1, iface, &IID_IServiceProvider, 0, 0, 0);
2332 return S_OK;
2333 }
2334
2335 if(*ppvObj)
2336 {
2337 IUnknown_AddRef(iface);
2338 return S_OK;
2339 }
2340
2341 return E_NOINTERFACE;
2342 }
2343
2344 static ULONG WINAPI IProfferServiceImpl_AddRef(IProfferService *iface)
2345 {
2346 IProfferServiceImpl *This = impl_from_IProfferService(iface);
2347 return InterlockedIncrement(&This->ref);
2348 }
2349
2350 static ULONG WINAPI IProfferServiceImpl_Release(IProfferService *iface)
2351 {
2352 IProfferServiceImpl *This = impl_from_IProfferService(iface);
2353 ULONG ref = InterlockedDecrement(&This->ref);
2354
2355 if (!ref)
2356 {
2357 HeapFree(GetProcessHeap(), 0, This);
2358 return 0;
2359 }
2360 return ref;
2361 }
2362
2363 static HRESULT WINAPI IProfferServiceImpl_ProfferService(IProfferService *iface,
2364 REFGUID service, IServiceProvider *pService, DWORD *pCookie)
2365 {
2366 *pCookie = 0xdeadbeef;
2367 add_call(&trace_got, 3, service, pService, pCookie, 0, 0);
2368 return S_OK;
2369 }
2370
2371 static HRESULT WINAPI IProfferServiceImpl_RevokeService(IProfferService *iface, DWORD cookie)
2372 {
2373 add_call(&trace_got, 4, (void*)(DWORD_PTR)cookie, 0, 0, 0, 0);
2374 return S_OK;
2375 }
2376
2377 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl =
2378 {
2379 IProfferServiceImpl_QueryInterface,
2380 IProfferServiceImpl_AddRef,
2381 IProfferServiceImpl_Release,
2382 IProfferServiceImpl_ProfferService,
2383 IProfferServiceImpl_RevokeService
2384 };
2385
2386 static void test_IUnknown_ProfferService(void)
2387 {
2388 IServiceProvider *provider = IServiceProviderImpl_Construct();
2389 IProfferService *proff = IProfferServiceImpl_Construct();
2390 static const GUID dummy_serviceid = { 0xdeadbeef };
2391 call_trace_t trace_expected;
2392 HRESULT hr;
2393 DWORD cookie;
2394
2395 /* on <=W2K platforms same ordinal used for another export with different
2396 prototype, so skipping using this indirect condition */
2397 if (is_win2k_and_lower)
2398 {
2399 win_skip("IUnknown_ProfferService is not available\n");
2400 return;
2401 }
2402
2403 /* null source pointer */
2404 hr = pIUnknown_ProfferService(NULL, &dummy_serviceid, 0, 0);
2405 ok(hr == E_FAIL, "got 0x%08x\n", hr);
2406
2407 /* expected trace:
2408 IUnknown_ProfferService( ptr1, serviceid, arg1, arg2);
2409 -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &provider );
2410 -> IServiceProvider_QueryService( provider, &IID_IProfferService, &IID_IProfferService, &proffer );
2411
2412 if (service pointer not null):
2413 -> IProfferService_ProfferService( proffer, serviceid, arg1, arg2 );
2414 else
2415 -> IProfferService_RevokeService( proffer, *arg2 );
2416 */
2417 init_call_trace(&trace_expected);
2418
2419 add_call(&trace_expected, 1, proff, &IID_IServiceProvider, 0, 0, 0);
2420 add_call(&trace_expected, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2421 add_call(&trace_expected, 3, &dummy_serviceid, provider, &cookie, 0, 0);
2422
2423 init_call_trace(&trace_got);
2424 cookie = 0;
2425 hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, provider, &cookie);
2426 ok(hr == S_OK, "got 0x%08x\n", hr);
2427 ok(cookie == 0xdeadbeef, "got %x\n", cookie);
2428
2429 ok_trace(&trace_expected, &trace_got);
2430 free_call_trace(&trace_got);
2431 free_call_trace(&trace_expected);
2432
2433 /* same with ::Revoke path */
2434 init_call_trace(&trace_expected);
2435
2436 add_call(&trace_expected, 1, proff, &IID_IServiceProvider, 0, 0, 0);
2437 add_call(&trace_expected, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2438 add_call(&trace_expected, 4, (void*)(DWORD_PTR)cookie, 0, 0, 0, 0);
2439
2440 init_call_trace(&trace_got);
2441 ok(cookie != 0, "got %x\n", cookie);
2442 hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, 0, &cookie);
2443 ok(hr == S_OK, "got 0x%08x\n", hr);
2444 ok(cookie == 0, "got %x\n", cookie);
2445 ok_trace(&trace_expected, &trace_got);
2446 free_call_trace(&trace_got);
2447 free_call_trace(&trace_expected);
2448
2449 IServiceProvider_Release(provider);
2450 IProfferService_Release(proff);
2451 }
2452
2453 static void test_SHCreateWorkerWindowA(void)
2454 {
2455 WNDCLASSA cliA;
2456 char classA[20];
2457 HWND hwnd;
2458 LONG_PTR ret;
2459 BOOL res;
2460
2461 if (is_win2k_and_lower)
2462 {
2463 win_skip("SHCreateWorkerWindowA not available\n");
2464 return;
2465 }
2466
2467 hwnd = pSHCreateWorkerWindowA(0, NULL, 0, 0, 0, 0);
2468 ok(hwnd != 0, "expected window\n");
2469
2470 GetClassName(hwnd, classA, 20);
2471 ok(lstrcmpA(classA, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA);
2472
2473 ret = GetWindowLongPtrA(hwnd, 0);
2474 ok(ret == 0, "got %ld\n", ret);
2475
2476 /* class info */
2477 memset(&cliA, 0, sizeof(cliA));
2478 res = GetClassInfoA(GetModuleHandle("shlwapi.dll"), "WorkerA", &cliA);
2479 ok(res, "failed to get class info\n");
2480 ok(cliA.style == 0, "got 0x%08x\n", cliA.style);
2481 ok(cliA.cbClsExtra == 0, "got %d\n", cliA.cbClsExtra);
2482 ok(cliA.cbWndExtra == sizeof(LONG_PTR), "got %d\n", cliA.cbWndExtra);
2483 ok(cliA.lpszMenuName == 0, "got %s\n", cliA.lpszMenuName);
2484
2485 DestroyWindow(hwnd);
2486
2487 /* set extra bytes */
2488 hwnd = pSHCreateWorkerWindowA(0, NULL, 0, 0, 0, 0xdeadbeef);
2489 ok(hwnd != 0, "expected window\n");
2490
2491 GetClassName(hwnd, classA, 20);
2492 ok(lstrcmpA(classA, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA);
2493
2494 ret = GetWindowLongPtrA(hwnd, 0);
2495 ok(ret == 0xdeadbeef, "got %ld\n", ret);
2496
2497 /* test exstyle */
2498 ret = GetWindowLongA(hwnd, GWL_EXSTYLE);
2499 ok(ret == WS_EX_WINDOWEDGE ||
2500 ret == (WS_EX_WINDOWEDGE|WS_EX_LAYOUTRTL) /* systems with RTL locale */, "0x%08lx\n", ret);
2501
2502 DestroyWindow(hwnd);
2503
2504 hwnd = pSHCreateWorkerWindowA(0, NULL, WS_EX_TOOLWINDOW, 0, 0, 0);
2505 ret = GetWindowLongA(hwnd, GWL_EXSTYLE);
2506 ok(ret == (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW) ||
2507 ret == (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW|WS_EX_LAYOUTRTL) /* systems with RTL locale */, "0x%08lx\n", ret);
2508 DestroyWindow(hwnd);
2509 }
2510
2511 static HRESULT WINAPI SF_QueryInterface(IShellFolder *iface,
2512 REFIID riid, void **ppv)
2513 {
2514 /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */
2515 ok(!IsEqualGUID(&IID_IShellFolder, riid),
2516 "Unexpected QI for IShellFolder\n");
2517 return E_NOINTERFACE;
2518 }
2519
2520 static ULONG WINAPI SF_AddRef(IShellFolder *iface)
2521 {
2522 return 2;
2523 }
2524
2525 static ULONG WINAPI SF_Release(IShellFolder *iface)
2526 {
2527 return 1;
2528 }
2529
2530 static HRESULT WINAPI SF_ParseDisplayName(IShellFolder *iface,
2531 HWND owner, LPBC reserved, LPOLESTR displayName, ULONG *eaten,
2532 LPITEMIDLIST *idl, ULONG *attr)
2533 {
2534 ok(0, "Didn't expect ParseDisplayName\n");
2535 return E_NOTIMPL;
2536 }
2537
2538 static HRESULT WINAPI SF_EnumObjects(IShellFolder *iface,
2539 HWND owner, SHCONTF flags, IEnumIDList **enm)
2540 {
2541 *enm = (IEnumIDList*)0xcafebabe;
2542 return S_OK;
2543 }
2544
2545 static HRESULT WINAPI SF_BindToObject(IShellFolder *iface,
2546 LPCITEMIDLIST idl, LPBC reserved, REFIID riid, void **obj)
2547 {
2548 ok(0, "Didn't expect BindToObject\n");
2549 return E_NOTIMPL;
2550 }
2551
2552 static HRESULT WINAPI SF_BindToStorage(IShellFolder *iface,
2553 LPCITEMIDLIST idl, LPBC reserved, REFIID riid, void **obj)
2554 {
2555 ok(0, "Didn't expect BindToStorage\n");
2556 return E_NOTIMPL;
2557 }
2558
2559 static HRESULT WINAPI SF_CompareIDs(IShellFolder *iface,
2560 LPARAM lparam, LPCITEMIDLIST idl1, LPCITEMIDLIST idl2)
2561 {
2562 ok(0, "Didn't expect CompareIDs\n");
2563 return E_NOTIMPL;
2564 }
2565
2566 static HRESULT WINAPI SF_CreateViewObject(IShellFolder *iface,
2567 HWND owner, REFIID riid, void **out)
2568 {
2569 ok(0, "Didn't expect CreateViewObject\n");
2570 return E_NOTIMPL;
2571 }
2572
2573 static HRESULT WINAPI SF_GetAttributesOf(IShellFolder *iface,
2574 UINT cidl, LPCITEMIDLIST *idl, SFGAOF *inOut)
2575 {
2576 ok(0, "Didn't expect GetAttributesOf\n");
2577 return E_NOTIMPL;
2578 }
2579
2580 static HRESULT WINAPI SF_GetUIObjectOf(IShellFolder *iface,
2581 HWND owner, UINT cidl, LPCITEMIDLIST *idls, REFIID riid, UINT *inOut,
2582 void **out)
2583 {
2584 ok(0, "Didn't expect GetUIObjectOf\n");
2585 return E_NOTIMPL;
2586 }
2587
2588 static HRESULT WINAPI SF_GetDisplayNameOf(IShellFolder *iface,
2589 LPCITEMIDLIST idl, SHGDNF flags, STRRET *name)
2590 {
2591 ok(0, "Didn't expect GetDisplayNameOf\n");
2592 return E_NOTIMPL;
2593 }
2594
2595 static HRESULT WINAPI SF_SetNameOf(IShellFolder *iface,
2596 HWND hwnd, LPCITEMIDLIST idl, LPCOLESTR name, SHGDNF flags,
2597 LPITEMIDLIST *idlOut)
2598 {
2599 ok(0, "Didn't expect SetNameOf\n");
2600 return E_NOTIMPL;
2601 }
2602
2603 static IShellFolderVtbl ShellFolderVtbl = {
2604 SF_QueryInterface,
2605 SF_AddRef,
2606 SF_Release,
2607 SF_ParseDisplayName,
2608 SF_EnumObjects,
2609 SF_BindToObject,
2610 SF_BindToStorage,
2611 SF_CompareIDs,
2612 SF_CreateViewObject,
2613 SF_GetAttributesOf,
2614 SF_GetUIObjectOf,
2615 SF_GetDisplayNameOf,
2616 SF_SetNameOf
2617 };
2618
2619 static IShellFolder ShellFolder = { &ShellFolderVtbl };
2620
2621 static void test_SHIShellFolder_EnumObjects(void)
2622 {
2623 IEnumIDList *enm;
2624 HRESULT hres;
2625 IShellFolder *folder;
2626
2627 if(!pSHIShellFolder_EnumObjects || is_win2k_and_lower){
2628 win_skip("SHIShellFolder_EnumObjects not available\n");
2629 return;
2630 }
2631
2632 if(0){
2633 /* NULL object crashes on Windows */
2634 pSHIShellFolder_EnumObjects(NULL, NULL, 0, NULL);
2635 }
2636
2637 /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */
2638 enm = (IEnumIDList*)0xdeadbeef;
2639 hres = pSHIShellFolder_EnumObjects(&ShellFolder, NULL, 0, &enm);
2640 ok(hres == S_OK, "SHIShellFolder_EnumObjects failed: 0x%08x\n", hres);
2641 ok(enm == (IEnumIDList*)0xcafebabe, "Didn't get expected enumerator location, instead: %p\n", enm);
2642
2643 /* SHIShellFolder_EnumObjects isn't strict about the IShellFolder object */
2644 hres = pSHGetDesktopFolder(&folder);
2645 ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
2646
2647 enm = NULL;
2648 hres = pSHIShellFolder_EnumObjects(folder, NULL, 0, &enm);
2649 ok(hres == S_OK, "SHIShellFolder_EnumObjects failed: 0x%08x\n", hres);
2650 ok(enm != NULL, "Didn't get an enumerator\n");
2651 if(enm)
2652 IEnumIDList_Release(enm);
2653
2654 IShellFolder_Release(folder);
2655 }
2656
2657 static void write_inifile(LPCWSTR filename)
2658 {
2659 DWORD written;
2660 HANDLE file;
2661
2662 static const char data[] =
2663 "[TestApp]\r\n"
2664 "AKey=1\r\n"
2665 "AnotherKey=asdf\r\n";
2666
2667 file = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
2668 if(file == INVALID_HANDLE_VALUE)
2669 return;
2670
2671 WriteFile(file, data, sizeof(data), &written, NULL);
2672
2673 CloseHandle(file);
2674 }
2675
2676 #define verify_inifile(f, e) r_verify_inifile(__LINE__, f, e)
2677 static void r_verify_inifile(unsigned l, LPCWSTR filename, LPCSTR exp)
2678 {
2679 HANDLE file;
2680 CHAR buf[1024];
2681 DWORD read;
2682
2683 file = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
2684 if(file == INVALID_HANDLE_VALUE)
2685 return;
2686
2687 ReadFile(file, buf, sizeof(buf) * sizeof(CHAR), &read, NULL);
2688 buf[read] = '\0';
2689
2690 CloseHandle(file);
2691
2692 ok_(__FILE__,l)(!strcmp(buf, exp), "Expected:\n%s\nGot:\n%s\n", exp,
2693 buf);
2694 }
2695
2696 static void test_SHGetIniString(void)
2697 {
2698 DWORD ret;
2699 WCHAR out[64] = {0};
2700
2701 static const WCHAR TestAppW[] = {'T','e','s','t','A','p','p',0};
2702 static const WCHAR TestIniW[] = {'C',':','\\','t','e','s','t','.','i','n','i',0};
2703 static const WCHAR AKeyW[] = {'A','K','e','y',0};
2704 static const WCHAR AnotherKeyW[] = {'A','n','o','t','h','e','r','K','e','y',0};
2705 static const WCHAR JunkKeyW[] = {'J','u','n','k','K','e','y',0};
2706
2707 if(!pSHGetIniStringW || is_win2k_and_lower){
2708 win_skip("SHGetIniStringW is not available\n");
2709 return;
2710 }
2711
2712 write_inifile(TestIniW);
2713
2714 if(0){
2715 /* these crash on Windows */
2716 pSHGetIniStringW(NULL, NULL, NULL, 0, NULL);
2717 pSHGetIniStringW(NULL, AKeyW, out, sizeof(out), TestIniW);
2718 pSHGetIniStringW(TestAppW, AKeyW, NULL, sizeof(out), TestIniW);
2719 }
2720
2721 ret = pSHGetIniStringW(TestAppW, AKeyW, out, 0, TestIniW);
2722 ok(ret == 0, "SHGetIniStringW should have given 0, instead: %d\n", ret);
2723
2724 /* valid arguments */
2725 ret = pSHGetIniStringW(TestAppW, NULL, out, sizeof(out), TestIniW);
2726 ok(broken(ret == 0) || /* win 98 */
2727 ret == 4, "SHGetIniStringW should have given 4, instead: %d\n", ret);
2728 ok(!lstrcmpW(out, AKeyW), "Expected %s, got: %s\n",
2729 wine_dbgstr_w(AKeyW), wine_dbgstr_w(out));
2730
2731 ret = pSHGetIniStringW(TestAppW, AKeyW, out, sizeof(out), TestIniW);
2732 ok(broken(ret == 0) || /* win 98 */
2733 ret == 1, "SHGetIniStringW should have given 1, instead: %d\n", ret);
2734 ok(broken(*out == 0) || /*win 98 */
2735 !strcmp_wa(out, "1"), "Expected L\"1\", got: %s\n", wine_dbgstr_w(out));
2736
2737 ret = pSHGetIniStringW(TestAppW, AnotherKeyW, out, sizeof(out), TestIniW);
2738 ok(broken(ret == 0) || /* win 98 */
2739 ret == 4, "SHGetIniStringW should have given 4, instead: %d\n", ret);
2740 ok(broken(*out == 0) || /* win 98 */
2741 !strcmp_wa(out, "asdf"), "Expected L\"asdf\", got: %s\n", wine_dbgstr_w(out));
2742
2743 ret = pSHGetIniStringW(TestAppW, JunkKeyW, out, sizeof(out), TestIniW);
2744 ok(ret == 0, "SHGetIniStringW should have given 0, instead: %d\n", ret);
2745 ok(*out == 0, "Expected L\"\", got: %s\n", wine_dbgstr_w(out));
2746
2747 DeleteFileW(TestIniW);
2748 }
2749
2750 static void test_SHSetIniString(void)
2751 {
2752 BOOL ret;
2753
2754 static const WCHAR TestAppW[] = {'T','e','s','t','A','p','p',0};
2755 static const WCHAR AnotherAppW[] = {'A','n','o','t','h','e','r','A','p','p',0};
2756 static const WCHAR TestIniW[] = {'C',':','\\','t','e','s','t','.','i','n','i',0};
2757 static const WCHAR AKeyW[] = {'A','K','e','y',0};
2758 static const WCHAR NewKeyW[] = {'N','e','w','K','e','y',0};
2759 static const WCHAR AValueW[] = {'A','V','a','l','u','e',0};
2760
2761 if(!pSHSetIniStringW || is_win2k_and_lower){
2762 win_skip("SHSetIniStringW is not available\n");
2763 return;
2764 }
2765
2766 write_inifile(TestIniW);
2767
2768 ret = pSHSetIniStringW(TestAppW, AKeyW, AValueW, TestIniW);
2769 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2770 todo_wine /* wine sticks an extra \r\n at the end of the file */
2771 verify_inifile(TestIniW, "[TestApp]\r\nAKey=AValue\r\nAnotherKey=asdf\r\n");
2772
2773 ret = pSHSetIniStringW(TestAppW, AKeyW, NULL, TestIniW);
2774 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2775 verify_inifile(TestIniW, "[TestApp]\r\nAnotherKey=asdf\r\n");
2776
2777 ret = pSHSetIniStringW(AnotherAppW, NewKeyW, AValueW, TestIniW);
2778 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2779 verify_inifile(TestIniW, "[TestApp]\r\nAnotherKey=asdf\r\n[AnotherApp]\r\nNewKey=AValue\r\n");
2780
2781 ret = pSHSetIniStringW(TestAppW, NULL, AValueW, TestIniW);
2782 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2783 verify_inifile(TestIniW, "[AnotherApp]\r\nNewKey=AValue\r\n");
2784
2785 DeleteFileW(TestIniW);
2786 }
2787
2788 enum _shellkey_flags {
2789 SHKEY_Root_HKCU = 0x1,
2790 SHKEY_Root_HKLM = 0x2,
2791 SHKEY_Key_Explorer = 0x00,
2792 SHKEY_Key_Shell = 0x10,
2793 SHKEY_Key_ShellNoRoam = 0x20,
2794 SHKEY_Key_Classes = 0x30,
2795 SHKEY_Subkey_Default = 0x0000,
2796 SHKEY_Subkey_ResourceName = 0x1000,
2797 SHKEY_Subkey_Handlers = 0x2000,
2798 SHKEY_Subkey_Associations = 0x3000,
2799 SHKEY_Subkey_Volatile = 0x4000,
2800 SHKEY_Subkey_MUICache = 0x5000,
2801 SHKEY_Subkey_FileExts = 0x6000
2802 };
2803
2804 static void test_SHGetShellKey(void)
2805 {
2806 static const WCHAR ShellFoldersW[] = { 'S','h','e','l','l',' ','F','o','l','d','e','r','s',0 };
2807 static const WCHAR WineTestW[] = { 'W','i','n','e','T','e','s','t',0 };
2808
2809 void *pPathBuildRootW = GetProcAddress(hShlwapi, "PathBuildRootW");
2810 DWORD *alloc_data, data, size;
2811 HKEY hkey;
2812 HRESULT hres;
2813
2814 if (!pSHGetShellKey)
2815 {
2816 win_skip("SHGetShellKey(ordinal 491) isn't available\n");
2817 return;
2818 }
2819
2820 /* some win2k */
2821 if (pPathBuildRootW && pPathBuildRootW == pSHGetShellKey)
2822 {
2823 win_skip("SHGetShellKey(ordinal 491) used for PathBuildRootW\n");
2824 return;
2825 }
2826
2827 if (is_win9x || is_win2k_and_lower)
2828 {
2829 win_skip("Ordinal 491 used for another call, skipping SHGetShellKey tests\n");
2830 return;
2831 }
2832
2833 /* Vista+ limits SHKEY enumeration values */
2834 SetLastError(0xdeadbeef);
2835 hkey = pSHGetShellKey(SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2836 if (hkey)
2837 {
2838 /* Tests not working on Vista+ */
2839 RegCloseKey(hkey);
2840
2841 hkey = pSHGetShellKey(SHKEY_Root_HKLM|SHKEY_Key_Classes, NULL, FALSE);
2842 ok(hkey != NULL, "hkey = NULL\n");
2843 RegCloseKey(hkey);
2844 }
2845
2846 hkey = pSHGetShellKey(SHKEY_Root_HKCU|SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2847 ok(hkey != NULL, "hkey = NULL\n");
2848 RegCloseKey(hkey);
2849
2850 hkey = pSHGetShellKey(SHKEY_Root_HKLM|SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2851 ok(hkey != NULL, "hkey = NULL\n");
2852 RegCloseKey(hkey);
2853
2854 hkey = pSHGetShellKey(SHKEY_Root_HKLM, WineTestW, FALSE);
2855 ok(hkey == NULL, "hkey != NULL\n");
2856
2857 hkey = pSHGetShellKey(SHKEY_Root_HKLM, NULL, FALSE);
2858 ok(hkey != NULL, "Can't open key\n");
2859 ok(SUCCEEDED(RegDeleteKeyW(hkey, WineTestW)), "Can't delete key\n");
2860 RegCloseKey(hkey);
2861
2862 hkey = pSHGetShellKey(SHKEY_Root_HKLM, WineTestW, TRUE);
2863 if (!hkey && GetLastError() == ERROR_ACCESS_DENIED)
2864 {
2865 skip("Not authorized to create keys\n");
2866 return;
2867 }
2868 ok(hkey != NULL, "Can't create key\n");
2869 RegCloseKey(hkey);
2870
2871 if (!pSKGetValueW || !pSKSetValueW || !pSKDeleteValueW || !pSKAllocValueW)
2872 {
2873 win_skip("SKGetValueW, SKSetValueW, SKDeleteValueW or SKAllocValueW not available\n");
2874 return;
2875 }
2876
2877 size = sizeof(data);
2878 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
2879 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres);
2880
2881 data = 1234;
2882 hres = pSKSetValueW(SHKEY_Root_HKLM, WineTestW, NULL, REG_DWORD, &data, sizeof(DWORD));
2883 ok(hres == S_OK, "hres = %x\n", hres);
2884
2885 size = 1;
2886 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, NULL, &size);
2887 ok(hres == S_OK, "hres = %x\n", hres);
2888 ok(size == sizeof(DWORD), "size = %d\n", size);
2889
2890 data = 0xdeadbeef;
2891 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
2892 ok(hres == S_OK, "hres = %x\n", hres);
2893 ok(size == sizeof(DWORD), "size = %d\n", size);
2894 ok(data == 1234, "data = %d\n", data);
2895
2896 hres = pSKAllocValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, (void**)&alloc_data, &size);
2897 ok(hres == S_OK, "hres= %x\n", hres);
2898 ok(size == sizeof(DWORD), "size = %d\n", size);
2899 if (SUCCEEDED(hres))
2900 {
2901 ok(*alloc_data == 1234, "*alloc_data = %d\n", *alloc_data);
2902 LocalFree(alloc_data);
2903 }
2904
2905 hres = pSKDeleteValueW(SHKEY_Root_HKLM, WineTestW, NULL);
2906 ok(hres == S_OK, "hres = %x\n", hres);
2907
2908 hres = pSKDeleteValueW(SHKEY_Root_HKLM, WineTestW, NULL);
2909 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres);
2910
2911 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
2912 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres);
2913
2914 hkey = pSHGetShellKey(SHKEY_Root_HKLM, NULL, FALSE);
2915 ok(hkey != NULL, "Can't create key\n");
2916 ok(SUCCEEDED(RegDeleteKeyW(hkey, WineTestW)), "Can't delete key\n");
2917 RegCloseKey(hkey);
2918 }
2919
2920 static void init_pointers(void)
2921 {
2922 #define MAKEFUNC(f, ord) (p##f = (void*)GetProcAddress(hShlwapi, (LPSTR)(ord)))
2923 MAKEFUNC(SHAllocShared, 7);
2924 MAKEFUNC(SHLockShared, 8);
2925 MAKEFUNC(SHUnlockShared, 9);
2926 MAKEFUNC(SHFreeShared, 10);
2927 MAKEFUNC(GetAcceptLanguagesA, 14);
2928 MAKEFUNC(SHSetWindowBits, 165);
2929 MAKEFUNC(SHSetParentHwnd, 167);
2930 MAKEFUNC(ConnectToConnectionPoint, 168);
2931 MAKEFUNC(SHSearchMapInt, 198);
2932 MAKEFUNC(SHCreateWorkerWindowA, 257);
2933 MAKEFUNC(GUIDFromStringA, 269);
2934 MAKEFUNC(SHPackDispParams, 282);
2935 MAKEFUNC(IConnectionPoint_InvokeWithCancel, 283);
2936 MAKEFUNC(IConnectionPoint_SimpleInvoke, 284);
2937 MAKEFUNC(SHGetIniStringW, 294);
2938 MAKEFUNC(SHSetIniStringW, 295);
2939 MAKEFUNC(SHFormatDateTimeA, 353);
2940 MAKEFUNC(SHFormatDateTimeW, 354);
2941 MAKEFUNC(SHIShellFolder_EnumObjects, 404);
2942 MAKEFUNC(SHGetObjectCompatFlags, 476);
2943 MAKEFUNC(IUnknown_QueryServiceExec, 484);
2944 MAKEFUNC(SHGetShellKey, 491);
2945 MAKEFUNC(SHPropertyBag_ReadLONG, 496);
2946 MAKEFUNC(IUnknown_ProfferService, 514);
2947 MAKEFUNC(SKGetValueW, 516);
2948 MAKEFUNC(SKSetValueW, 517);
2949 MAKEFUNC(SKDeleteValueW, 518);
2950 MAKEFUNC(SKAllocValueW, 519);
2951 #undef MAKEFUNC
2952 }
2953
2954 static void test_SHSetParentHwnd(void)
2955 {
2956 HWND hwnd, hwnd2, ret;
2957 DWORD style;
2958
2959 if (!pSHSetParentHwnd)
2960 {
2961 win_skip("SHSetParentHwnd not available\n");
2962 return;
2963 }
2964
2965 hwnd = CreateWindowA("Button", "", WS_VISIBLE, 0, 0, 10, 10, NULL, NULL, NULL, NULL);
2966 ok(hwnd != NULL, "got %p\n", hwnd);
2967
2968 hwnd2 = CreateWindowA("Button", "", WS_VISIBLE | WS_CHILD, 0, 0, 10, 10, hwnd, NULL, NULL, NULL);
2969 ok(hwnd2 != NULL, "got %p\n", hwnd2);
2970
2971 /* null params */
2972 ret = pSHSetParentHwnd(NULL, NULL);
2973 ok(ret == NULL, "got %p\n", ret);
2974
2975 /* set to no parent while already no parent present */
2976 ret = GetParent(hwnd);
2977 ok(ret == NULL, "got %p\n", ret);
2978 style = GetWindowLongA(hwnd, GWL_STYLE);
2979 ok((style & (WS_POPUP|WS_CHILD)) == 0, "got style 0x%08x\n", style);
2980 ret = pSHSetParentHwnd(hwnd, NULL);
2981 ok(ret == NULL, "got %p\n", ret);
2982 style = GetWindowLongA(hwnd, GWL_STYLE);
2983 ok((style & (WS_POPUP|WS_CHILD)) == 0, "got style 0x%08x\n", style);
2984
2985 /* reset to null parent from not null */
2986 ret = GetParent(hwnd2);
2987 ok(ret == hwnd, "got %p\n", ret);
2988 style = GetWindowLongA(hwnd2, GWL_STYLE);
2989 ok((style & (WS_POPUP|WS_CHILD)) == WS_CHILD, "got style 0x%08x\n", style);
2990 ret = pSHSetParentHwnd(hwnd2, NULL);
2991 ok(ret == NULL, "got %p\n", ret);
2992 style = GetWindowLongA(hwnd2, GWL_STYLE);
2993 ok((style & (WS_POPUP|WS_CHILD)) == WS_POPUP, "got style 0x%08x\n", style);
2994 ret = GetParent(hwnd2);
2995 ok(ret == NULL, "got %p\n", ret);
2996
2997 /* set parent back */
2998 style = GetWindowLongA(hwnd2, GWL_STYLE);
2999 SetWindowLongA(hwnd2, GWL_STYLE, style & ~(WS_CHILD|WS_POPUP));
3000 style = GetWindowLongA(hwnd2, GWL_STYLE);
3001 ok((style & (WS_CHILD|WS_POPUP)) == 0, "got 0x%08x\n", style);
3002
3003 ret = pSHSetParentHwnd(hwnd2, hwnd);
3004 todo_wine ok(ret == NULL, "got %p\n", ret);
3005
3006 style = GetWindowLongA(hwnd2, GWL_STYLE);
3007 ok((style & (WS_POPUP|WS_CHILD)) == WS_CHILD, "got style 0x%08x\n", style);
3008 ret = GetParent(hwnd2);
3009 ok(ret == hwnd, "got %p\n", ret);
3010
3011 /* try to set same parent again */
3012 /* with WS_POPUP */
3013 style = GetWindowLongA(hwnd2, GWL_STYLE);
3014 SetWindowLongA(hwnd2, GWL_STYLE, style | WS_POPUP);
3015 ret = pSHSetParentHwnd(hwnd2, hwnd);
3016 todo_wine ok(ret == NULL, "got %p\n", ret);
3017 style = GetWindowLongA(hwnd2, GWL_STYLE);
3018 ok((style & (WS_CHILD|WS_POPUP)) == WS_CHILD, "got 0x%08x\n", style);
3019 ret = GetParent(hwnd2);
3020 ok(ret == hwnd, "got %p\n", ret);
3021
3022 /* without WS_POPUP */
3023 style = GetWindowLongA(hwnd2, GWL_STYLE);
3024 SetWindowLongA(hwnd2, GWL_STYLE, style | ~WS_POPUP);
3025 ret = pSHSetParentHwnd(hwnd2, hwnd);
3026 todo_wine ok(ret == hwnd, "got %p\n", ret);
3027 style = GetWindowLongA(hwnd2, GWL_STYLE);
3028 ok((style & (WS_CHILD|WS_POPUP)) == WS_CHILD, "got 0x%08x\n", style);
3029 ret = GetParent(hwnd2);
3030 ok(ret == hwnd, "got %p\n", ret);
3031
3032 DestroyWindow(hwnd);
3033 DestroyWindow(hwnd2);
3034 }
3035
3036 START_TEST(ordinal)
3037 {
3038 hShlwapi = GetModuleHandleA("shlwapi.dll");
3039 is_win2k_and_lower = GetProcAddress(hShlwapi, "StrChrNW") == 0;
3040 is_win9x = GetProcAddress(hShlwapi, (LPSTR)99) == 0; /* StrCpyNXA */
3041
3042 /* SHCreateStreamOnFileEx was introduced in shlwapi v6.0 */
3043 if(!GetProcAddress(hShlwapi, "SHCreateStreamOnFileEx")){
3044 win_skip("Too old shlwapi version\n");
3045 return;
3046 }
3047
3048 init_pointers();
3049
3050 hmlang = LoadLibraryA("mlang.dll");
3051 pLcidToRfc1766A = (void *)GetProcAddress(hmlang, "LcidToRfc1766A");
3052
3053 hshell32 = LoadLibraryA("shell32.dll");
3054 pSHGetDesktopFolder = (void *)GetProcAddress(hshell32, "SHGetDesktopFolder");
3055
3056 test_GetAcceptLanguagesA();
3057 test_SHSearchMapInt();
3058 test_alloc_shared();
3059 test_fdsa();
3060 test_GetShellSecurityDescriptor();
3061 test_SHPackDispParams();
3062 test_IConnectionPoint();
3063 test_SHPropertyBag_ReadLONG();
3064 test_SHSetWindowBits();
3065 test_SHFormatDateTimeA();
3066 test_SHFormatDateTimeW();
3067 test_SHGetObjectCompatFlags();
3068 test_IUnknown_QueryServiceExec();
3069 test_IUnknown_ProfferService();
3070 test_SHCreateWorkerWindowA();
3071 test_SHIShellFolder_EnumObjects();
3072 test_SHGetIniString();
3073 test_SHSetIniString();
3074 test_SHGetShellKey();
3075 test_SHSetParentHwnd();
3076
3077 FreeLibrary(hshell32);
3078 FreeLibrary(hmlang);
3079 }
3080
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.