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