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