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