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