shlwapi: Use E_NOT_SUFFICIENT_BUFFER definition.
[wine.git] / dlls / shlwapi / tests / ordinal.c
blobd8a4f680321d3e264db7de05713dc1fb33d2b696
1 /* Unit test suite for SHLWAPI ordinal functions
3 * Copyright 2004 Jon Griffiths
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.
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.
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
20 #include <stdio.h>
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"
37 /* Function ptrs for ordinal calls */
38 static HMODULE hShlwapi;
39 static BOOL is_win2k_and_lower;
40 static BOOL is_win9x;
42 static int (WINAPI *pSHSearchMapInt)(const int*,const int*,int,int);
43 static HRESULT (WINAPI *pGetAcceptLanguagesA)(LPSTR,LPDWORD);
45 static HANDLE (WINAPI *pSHAllocShared)(LPCVOID,DWORD,DWORD);
46 static LPVOID (WINAPI *pSHLockShared)(HANDLE,DWORD);
47 static BOOL (WINAPI *pSHUnlockShared)(LPVOID);
48 static BOOL (WINAPI *pSHFreeShared)(HANDLE,DWORD);
49 static HANDLE (WINAPI *pSHMapHandle)(HANDLE,DWORD,DWORD,DWORD,DWORD);
50 static HRESULT(WINAPIV *pSHPackDispParams)(DISPPARAMS*,VARIANTARG*,UINT,...);
51 static HRESULT(WINAPI *pIConnectionPoint_SimpleInvoke)(IConnectionPoint*,DISPID,DISPPARAMS*);
52 static HRESULT(WINAPI *pIConnectionPoint_InvokeWithCancel)(IConnectionPoint*,DISPID,DISPPARAMS*,DWORD,DWORD);
53 static HRESULT(WINAPI *pConnectToConnectionPoint)(IUnknown*,REFIID,BOOL,IUnknown*, LPDWORD,IConnectionPoint **);
54 static HRESULT(WINAPI *pSHPropertyBag_ReadLONG)(IPropertyBag *,LPCWSTR,LPLONG);
55 static LONG (WINAPI *pSHSetWindowBits)(HWND, INT, UINT, UINT);
56 static INT (WINAPI *pSHFormatDateTimeA)(const FILETIME UNALIGNED*, DWORD*, LPSTR, UINT);
57 static INT (WINAPI *pSHFormatDateTimeW)(const FILETIME UNALIGNED*, DWORD*, LPWSTR, UINT);
58 static DWORD (WINAPI *pSHGetObjectCompatFlags)(IUnknown*, const CLSID*);
59 static BOOL (WINAPI *pGUIDFromStringA)(LPSTR, CLSID *);
60 static HRESULT (WINAPI *pIUnknown_QueryServiceExec)(IUnknown*, REFIID, const GUID*, DWORD, DWORD, VARIANT*, VARIANT*);
61 static HRESULT (WINAPI *pIUnknown_ProfferService)(IUnknown*, REFGUID, IServiceProvider*, DWORD*);
62 static HWND (WINAPI *pSHCreateWorkerWindowA)(LONG, HWND, DWORD, DWORD, HMENU, LONG_PTR);
63 static HRESULT (WINAPI *pSHIShellFolder_EnumObjects)(LPSHELLFOLDER, HWND, SHCONTF, IEnumIDList**);
64 static DWORD (WINAPI *pSHGetIniStringW)(LPCWSTR, LPCWSTR, LPWSTR, DWORD, LPCWSTR);
65 static BOOL (WINAPI *pSHSetIniStringW)(LPCWSTR, LPCWSTR, LPCWSTR, LPCWSTR);
66 static HKEY (WINAPI *pSHGetShellKey)(DWORD, LPCWSTR, BOOL);
67 static HRESULT (WINAPI *pSKGetValueW)(DWORD, LPCWSTR, LPCWSTR, DWORD*, void*, DWORD*);
68 static HRESULT (WINAPI *pSKSetValueW)(DWORD, LPCWSTR, LPCWSTR, DWORD, void*, DWORD);
69 static HRESULT (WINAPI *pSKDeleteValueW)(DWORD, LPCWSTR, LPCWSTR);
70 static HRESULT (WINAPI *pSKAllocValueW)(DWORD, LPCWSTR, LPCWSTR, DWORD*, void**, DWORD*);
71 static HWND (WINAPI *pSHSetParentHwnd)(HWND, HWND);
73 static HMODULE hmlang;
74 static HRESULT (WINAPI *pLcidToRfc1766A)(LCID, LPSTR, INT);
76 static HMODULE hshell32;
77 static HRESULT (WINAPI *pSHGetDesktopFolder)(IShellFolder**);
79 static const CHAR ie_international[] = {
80 'S','o','f','t','w','a','r','e','\\',
81 'M','i','c','r','o','s','o','f','t','\\',
82 'I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r','\\',
83 'I','n','t','e','r','n','a','t','i','o','n','a','l',0};
84 static const CHAR acceptlanguage[] = {
85 'A','c','c','e','p','t','L','a','n','g','u','a','g','e',0};
87 static int strcmp_wa(LPCWSTR strw, const char *stra)
89 CHAR buf[512];
90 WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL);
91 return lstrcmpA(stra, buf);
94 typedef struct {
95 int id;
96 const void *args[5];
97 } call_entry_t;
99 typedef struct {
100 call_entry_t *calls;
101 int count;
102 int alloc;
103 } call_trace_t;
105 static void init_call_trace(call_trace_t *ctrace)
107 ctrace->alloc = 10;
108 ctrace->count = 0;
109 ctrace->calls = HeapAlloc(GetProcessHeap(), 0, sizeof(call_entry_t) * ctrace->alloc);
112 static void free_call_trace(const call_trace_t *ctrace)
114 HeapFree(GetProcessHeap(), 0, ctrace->calls);
117 static void add_call(call_trace_t *ctrace, int id, const void *arg0,
118 const void *arg1, const void *arg2, const void *arg3, const void *arg4)
120 call_entry_t call;
122 call.id = id;
123 call.args[0] = arg0;
124 call.args[1] = arg1;
125 call.args[2] = arg2;
126 call.args[3] = arg3;
127 call.args[4] = arg4;
129 if (ctrace->count == ctrace->alloc)
131 ctrace->alloc *= 2;
132 ctrace->calls = HeapReAlloc(GetProcessHeap(),0, ctrace->calls, ctrace->alloc*sizeof(call_entry_t));
135 ctrace->calls[ctrace->count++] = call;
138 static void ok_trace_(call_trace_t *texpected, call_trace_t *tgot, int line)
140 if (texpected->count == tgot->count)
142 INT i;
143 /* compare */
144 for (i = 0; i < texpected->count; i++)
146 call_entry_t *expected = &texpected->calls[i];
147 call_entry_t *got = &tgot->calls[i];
148 INT j;
150 ok_(__FILE__, line)(expected->id == got->id, "got different ids %d: %d, %d\n", i+1, expected->id, got->id);
152 for (j = 0; j < 5; j++)
154 ok_(__FILE__, line)(expected->args[j] == got->args[j], "got different args[%d] for %d: %p, %p\n", j, i+1,
155 expected->args[j], got->args[j]);
159 else
160 ok_(__FILE__, line)(0, "traces length mismatch\n");
163 #define ok_trace(a, b) ok_trace_(a, b, __LINE__)
165 /* trace of actually made calls */
166 static call_trace_t trace_got;
168 static void test_GetAcceptLanguagesA(void)
170 static LPCSTR table[] = {"de,en-gb;q=0.7,en;q=0.3",
171 "de,en;q=0.3,en-gb;q=0.7", /* sorting is ignored */
172 "winetest", /* content is ignored */
173 "de-de,de;q=0.5",
174 "de",
175 NULL};
177 DWORD exactsize;
178 char original[512];
179 char language[32];
180 char buffer[64];
181 HKEY hroot = NULL;
182 LONG res_query = ERROR_SUCCESS;
183 LONG lres;
184 HRESULT hr;
185 DWORD maxlen = sizeof(buffer) - 2;
186 DWORD len;
187 LCID lcid;
188 LPCSTR entry;
189 INT i = 0;
191 if (!pGetAcceptLanguagesA) {
192 win_skip("GetAcceptLanguagesA is not available\n");
193 return;
196 lcid = GetUserDefaultLCID();
198 /* Get the original Value */
199 lres = RegOpenKeyA(HKEY_CURRENT_USER, ie_international, &hroot);
200 if (lres) {
201 skip("RegOpenKey(%s) failed: %d\n", ie_international, lres);
202 return;
204 len = sizeof(original);
205 original[0] = 0;
206 res_query = RegQueryValueExA(hroot, acceptlanguage, 0, NULL, (PBYTE)original, &len);
208 RegDeleteValueA(hroot, acceptlanguage);
210 /* Some windows versions use "lang-COUNTRY" as default */
211 memset(language, 0, sizeof(language));
212 len = GetLocaleInfoA(lcid, LOCALE_SISO639LANGNAME, language, sizeof(language));
214 if (len) {
215 lstrcatA(language, "-");
216 memset(buffer, 0, sizeof(buffer));
217 len = GetLocaleInfoA(lcid, LOCALE_SISO3166CTRYNAME, buffer, sizeof(buffer) - len - 1);
218 lstrcatA(language, buffer);
220 else
222 /* LOCALE_SNAME has additional parts in some languages. Try only as last chance */
223 memset(language, 0, sizeof(language));
224 len = GetLocaleInfoA(lcid, LOCALE_SNAME, language, sizeof(language));
227 /* get the default value */
228 len = maxlen;
229 memset(buffer, '#', maxlen);
230 buffer[maxlen] = 0;
231 hr = pGetAcceptLanguagesA( buffer, &len);
233 if (hr != S_OK) {
234 win_skip("GetAcceptLanguagesA failed with 0x%x\n", hr);
235 goto restore_original;
238 if (lstrcmpA(buffer, language)) {
239 /* some windows versions use "lang" or "lang-country" as default */
240 language[0] = 0;
241 if (pLcidToRfc1766A) {
242 hr = pLcidToRfc1766A(lcid, language, sizeof(language));
243 ok(hr == S_OK, "LcidToRfc1766A returned 0x%x and %s\n", hr, language);
247 ok(!lstrcmpA(buffer, language),
248 "have '%s' (searching for '%s')\n", language, buffer);
250 if (lstrcmpA(buffer, language)) {
251 win_skip("no more ideas, how to build the default language '%s'\n", buffer);
252 goto restore_original;
255 trace("detected default: %s\n", language);
256 while ((entry = table[i])) {
258 exactsize = lstrlenA(entry);
260 lres = RegSetValueExA(hroot, acceptlanguage, 0, REG_SZ, (const BYTE *) entry, exactsize + 1);
261 ok(!lres, "got %d for RegSetValueExA: %s\n", lres, entry);
263 /* len includes space for the terminating 0 before vista/w2k8 */
264 len = exactsize + 2;
265 memset(buffer, '#', maxlen);
266 buffer[maxlen] = 0;
267 hr = pGetAcceptLanguagesA( buffer, &len);
268 ok(((hr == E_INVALIDARG) && (len == 0)) ||
269 (SUCCEEDED(hr) &&
270 ((len == exactsize) || (len == exactsize+1)) &&
271 !lstrcmpA(buffer, entry)),
272 "+2_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
274 len = exactsize + 1;
275 memset(buffer, '#', maxlen);
276 buffer[maxlen] = 0;
277 hr = pGetAcceptLanguagesA( buffer, &len);
278 ok(((hr == E_INVALIDARG) && (len == 0)) ||
279 (SUCCEEDED(hr) &&
280 ((len == exactsize) || (len == exactsize+1)) &&
281 !lstrcmpA(buffer, entry)),
282 "+1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
284 len = exactsize;
285 memset(buffer, '#', maxlen);
286 buffer[maxlen] = 0;
287 hr = pGetAcceptLanguagesA( buffer, &len);
289 /* There is no space for the string in the registry.
290 When the buffer is large enough, the default language is returned
292 When the buffer is too small for that fallback, win7_32 and w2k8_64
293 fail with E_NOT_SUFFICIENT_BUFFER, win8 fails with HRESULT_FROM_WIN32(ERROR_MORE_DATA),
294 other versions succeed and return a partial result while older os succeed
295 and overflow the buffer */
297 ok(((hr == E_INVALIDARG) && (len == 0)) ||
298 (((hr == S_OK) && !lstrcmpA(buffer, language) && (len == lstrlenA(language))) ||
299 ((hr == S_OK) && !memcmp(buffer, language, len)) ||
300 ((hr == E_NOT_SUFFICIENT_BUFFER) && !len) ||
301 ((hr == __HRESULT_FROM_WIN32(ERROR_MORE_DATA)) && len == exactsize)),
302 "==_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
304 if (exactsize > 1) {
305 len = exactsize - 1;
306 memset(buffer, '#', maxlen);
307 buffer[maxlen] = 0;
308 hr = pGetAcceptLanguagesA( buffer, &len);
309 ok(((hr == E_INVALIDARG) && (len == 0)) ||
310 (((hr == S_OK) && !lstrcmpA(buffer, language) && (len == lstrlenA(language))) ||
311 ((hr == S_OK) && !memcmp(buffer, language, len)) ||
312 ((hr == E_NOT_SUFFICIENT_BUFFER) && !len) ||
313 ((hr == __HRESULT_FROM_WIN32(ERROR_MORE_DATA)) && len == exactsize - 1)),
314 "-1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
317 len = 1;
318 memset(buffer, '#', maxlen);
319 buffer[maxlen] = 0;
320 hr = pGetAcceptLanguagesA( buffer, &len);
321 ok(((hr == E_INVALIDARG) && (len == 0)) ||
322 (((hr == S_OK) && !lstrcmpA(buffer, language) && (len == lstrlenA(language))) ||
323 ((hr == S_OK) && !memcmp(buffer, language, len)) ||
324 ((hr == E_NOT_SUFFICIENT_BUFFER) && !len) ||
325 ((hr == __HRESULT_FROM_WIN32(ERROR_MORE_DATA)) && len == 1)),
326 "=1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
328 len = maxlen;
329 hr = pGetAcceptLanguagesA( NULL, &len);
331 /* w2k3 and below: E_FAIL and untouched len,
332 since w2k8: S_OK and needed size (excluding 0), win8 S_OK and size including 0. */
333 ok( ((hr == S_OK) && ((len == exactsize) || (len == exactsize + 1))) ||
334 ((hr == E_FAIL) && (len == maxlen)),
335 "NULL,max #%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
337 i++;
340 /* without a value in the registry, a default language is returned */
341 RegDeleteValueA(hroot, acceptlanguage);
343 len = maxlen;
344 memset(buffer, '#', maxlen);
345 buffer[maxlen] = 0;
346 hr = pGetAcceptLanguagesA( buffer, &len);
347 ok( ((hr == S_OK) && (len == lstrlenA(language))),
348 "max: got 0x%x with %d and %s (expected S_OK with %d and '%s'\n",
349 hr, len, buffer, lstrlenA(language), language);
351 len = 2;
352 memset(buffer, '#', maxlen);
353 buffer[maxlen] = 0;
354 hr = pGetAcceptLanguagesA( buffer, &len);
355 ok( (((hr == S_OK) || (hr == E_INVALIDARG)) && !memcmp(buffer, language, len)) ||
356 ((hr == E_NOT_SUFFICIENT_BUFFER) && !len) ||
357 ((hr == __HRESULT_FROM_WIN32(ERROR_CANNOT_COPY)) && !len),
358 "=2: got 0x%x with %d and %s\n", hr, len, buffer);
360 len = 1;
361 memset(buffer, '#', maxlen);
362 buffer[maxlen] = 0;
363 hr = pGetAcceptLanguagesA( buffer, &len);
364 /* When the buffer is too small, win7_32 and w2k8_64 and above fail with
365 E_NOT_SUFFICIENT_BUFFER, win8 ERROR_CANNOT_COPY,
366 other versions succeed and return a partial 0 terminated result while other versions
367 fail with E_INVALIDARG and return a partial unterminated result */
368 ok( (((hr == S_OK) || (hr == E_INVALIDARG)) && !memcmp(buffer, language, len)) ||
369 ((hr == E_NOT_SUFFICIENT_BUFFER) && !len) ||
370 ((hr == __HRESULT_FROM_WIN32(ERROR_CANNOT_COPY)) && !len),
371 "=1: got 0x%x with %d and %s\n", hr, len, buffer);
373 len = 0;
374 memset(buffer, '#', maxlen);
375 buffer[maxlen] = 0;
376 hr = pGetAcceptLanguagesA( buffer, &len);
377 /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG, win8 ERROR_CANNOT_COPY */
378 ok((hr == E_FAIL) || (hr == E_INVALIDARG) || (hr == __HRESULT_FROM_WIN32(ERROR_CANNOT_COPY)),
379 "got 0x%x\n", hr);
381 memset(buffer, '#', maxlen);
382 buffer[maxlen] = 0;
383 hr = pGetAcceptLanguagesA( buffer, NULL);
384 /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG */
385 ok((hr == E_FAIL) || (hr == E_INVALIDARG),
386 "got 0x%x (expected E_FAIL or E_INVALIDARG)\n", hr);
389 hr = pGetAcceptLanguagesA( NULL, NULL);
390 /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG */
391 ok((hr == E_FAIL) || (hr == E_INVALIDARG),
392 "got 0x%x (expected E_FAIL or E_INVALIDARG)\n", hr);
394 restore_original:
395 if (!res_query) {
396 len = lstrlenA(original);
397 lres = RegSetValueExA(hroot, acceptlanguage, 0, REG_SZ, (const BYTE *) original, len ? len + 1: 0);
398 ok(!lres, "RegSetValueEx(%s) failed: %d\n", original, lres);
400 else
402 RegDeleteValueA(hroot, acceptlanguage);
404 RegCloseKey(hroot);
407 static void test_SHSearchMapInt(void)
409 int keys[8], values[8];
410 int i = 0;
412 if (!pSHSearchMapInt)
413 return;
415 memset(keys, 0, sizeof(keys));
416 memset(values, 0, sizeof(values));
417 keys[0] = 99; values[0] = 101;
419 /* NULL key/value lists crash native, so skip testing them */
421 /* 1 element */
422 i = pSHSearchMapInt(keys, values, 1, keys[0]);
423 ok(i == values[0], "Len 1, expected %d, got %d\n", values[0], i);
425 /* Key doesn't exist */
426 i = pSHSearchMapInt(keys, values, 1, 100);
427 ok(i == -1, "Len 1 - bad key, expected -1, got %d\n", i);
429 /* Len = 0 => not found */
430 i = pSHSearchMapInt(keys, values, 0, keys[0]);
431 ok(i == -1, "Len 1 - passed len 0, expected -1, got %d\n", i);
433 /* 2 elements, len = 1 */
434 keys[1] = 98; values[1] = 102;
435 i = pSHSearchMapInt(keys, values, 1, keys[1]);
436 ok(i == -1, "Len 1 - array len 2, expected -1, got %d\n", i);
438 /* 2 elements, len = 2 */
439 i = pSHSearchMapInt(keys, values, 2, keys[1]);
440 ok(i == values[1], "Len 2, expected %d, got %d\n", values[1], i);
442 /* Searches forward */
443 keys[2] = 99; values[2] = 103;
444 i = pSHSearchMapInt(keys, values, 3, keys[0]);
445 ok(i == values[0], "Len 3, expected %d, got %d\n", values[0], i);
448 struct shared_struct
450 DWORD value;
451 HANDLE handle;
454 static void test_alloc_shared(int argc, char **argv)
456 char cmdline[MAX_PATH];
457 PROCESS_INFORMATION pi;
458 STARTUPINFOA si = { 0 };
459 DWORD procid;
460 HANDLE hmem, hmem2 = 0;
461 struct shared_struct val, *p;
462 BOOL ret;
464 procid=GetCurrentProcessId();
465 hmem=pSHAllocShared(NULL,10,procid);
466 ok(hmem!=NULL,"SHAllocShared(NULL...) failed: %u\n", GetLastError());
467 ret = pSHFreeShared(hmem, procid);
468 ok( ret, "SHFreeShared failed: %u\n", GetLastError());
470 val.value = 0x12345678;
471 val.handle = 0;
472 hmem = pSHAllocShared(&val, sizeof(val), procid);
473 ok(hmem!=NULL,"SHAllocShared(NULL...) failed: %u\n", GetLastError());
475 p=pSHLockShared(hmem,procid);
476 ok(p!=NULL,"SHLockShared failed: %u\n", GetLastError());
477 if (p!=NULL)
478 ok(p->value == 0x12345678, "Wrong value in shared memory: %d instead of %d\n", p->value, 0x12345678);
479 ret = pSHUnlockShared(p);
480 ok( ret, "SHUnlockShared failed: %u\n", GetLastError());
482 sprintf(cmdline, "%s %s %d %p", argv[0], argv[1], procid, hmem);
483 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
484 ok(ret, "could not create child process error: %u\n", GetLastError());
485 if (ret)
487 winetest_wait_child_process(pi.hProcess);
488 CloseHandle(pi.hThread);
489 CloseHandle(pi.hProcess);
491 p = pSHLockShared(hmem, procid);
492 ok(p != NULL,"SHLockShared failed: %u\n", GetLastError());
493 if (p != NULL && p->value != 0x12345678)
495 ok(p->value == 0x12345679, "Wrong value in shared memory: %d instead of %d\n", p->value, 0x12345679);
496 hmem2 = p->handle;
497 ok(hmem2 != NULL, "Expected handle in shared memory\n");
499 ret = pSHUnlockShared(p);
500 ok(ret, "SHUnlockShared failed: %u\n", GetLastError());
503 ret = pSHFreeShared(hmem, procid);
504 ok( ret, "SHFreeShared failed: %u\n", GetLastError());
506 if (hmem2)
508 p = pSHLockShared(hmem2, procid);
509 ok(p != NULL,"SHLockShared failed: %u\n", GetLastError());
510 if (p != NULL)
511 ok(p->value == 0xDEADBEEF, "Wrong value in shared memory: %d instead of %d\n", p->value, 0xDEADBEEF);
512 ret = pSHUnlockShared(p);
513 ok(ret, "SHUnlockShared failed: %u\n", GetLastError());
515 ret = pSHFreeShared(hmem2, procid);
516 ok(ret, "SHFreeShared failed: %u\n", GetLastError());
520 static void test_alloc_shared_remote(DWORD procid, HANDLE hmem)
522 struct shared_struct val, *p;
523 HANDLE hmem2;
524 BOOL ret;
526 /* test directly accessing shared memory of a remote process */
527 p = pSHLockShared(hmem, procid);
528 ok(p != NULL || broken(p == NULL) /* Windows 7/8 */, "SHLockShared failed: %u\n", GetLastError());
529 if (p == NULL)
531 win_skip("Subprocess failed to modify shared memory, skipping test\n");
532 return;
535 ok(p->value == 0x12345678, "Wrong value in shared memory: %d instead of %d\n", p->value, 0x12345678);
536 p->value++;
538 val.value = 0xDEADBEEF;
539 val.handle = 0;
540 p->handle = pSHAllocShared(&val, sizeof(val), procid);
541 ok(p->handle != NULL, "SHAllocShared failed: %u\n", GetLastError());
543 ret = pSHUnlockShared(p);
544 ok(ret, "SHUnlockShared failed: %u\n", GetLastError());
546 /* test SHMapHandle */
547 hmem2 = pSHMapHandle(hmem, procid, GetCurrentProcessId(), 0, 0);
549 /* It seems like Windows Vista/2008 uses a different internal implementation
550 * for shared memory, and calling SHMapHandle fails with ERROR_INVALID_HANDLE. */
551 ok(hmem2 != NULL || broken(hmem2 == NULL && GetLastError() == ERROR_INVALID_HANDLE),
552 "SHMapHandle failed: %u\n", GetLastError());
553 if (hmem2 == NULL && GetLastError() == ERROR_INVALID_HANDLE)
555 win_skip("Subprocess failed to map shared memory, skipping test\n");
556 return;
559 p = pSHLockShared(hmem2, GetCurrentProcessId());
560 ok(p != NULL, "SHLockShared failed: %u\n", GetLastError());
562 if (p != NULL)
563 ok(p->value == 0x12345679, "Wrong value in shared memory: %d instead of %d\n", p->value, 0x12345679);
565 ret = pSHUnlockShared(p);
566 ok(ret, "SHUnlockShared failed: %u\n", GetLastError());
568 ret = pSHFreeShared(hmem2, GetCurrentProcessId());
569 ok(ret, "SHFreeShared failed: %u\n", GetLastError());
572 static void test_fdsa(void)
574 typedef struct
576 DWORD num_items; /* Number of elements inserted */
577 void *mem; /* Ptr to array */
578 DWORD blocks_alloced; /* Number of elements allocated */
579 BYTE inc; /* Number of elements to grow by when we need to expand */
580 BYTE block_size; /* Size in bytes of an element */
581 BYTE flags; /* Flags */
582 } FDSA_info;
584 BOOL (WINAPI *pFDSA_Initialize)(DWORD block_size, DWORD inc, FDSA_info *info, void *mem,
585 DWORD init_blocks);
586 BOOL (WINAPI *pFDSA_Destroy)(FDSA_info *info);
587 DWORD (WINAPI *pFDSA_InsertItem)(FDSA_info *info, DWORD where, const void *block);
588 BOOL (WINAPI *pFDSA_DeleteItem)(FDSA_info *info, DWORD where);
590 FDSA_info info;
591 int block_size = 10, init_blocks = 4, inc = 2;
592 DWORD ret;
593 char *mem;
595 pFDSA_Initialize = (void *)GetProcAddress(hShlwapi, (LPSTR)208);
596 pFDSA_Destroy = (void *)GetProcAddress(hShlwapi, (LPSTR)209);
597 pFDSA_InsertItem = (void *)GetProcAddress(hShlwapi, (LPSTR)210);
598 pFDSA_DeleteItem = (void *)GetProcAddress(hShlwapi, (LPSTR)211);
600 mem = HeapAlloc(GetProcessHeap(), 0, block_size * init_blocks);
601 memset(&info, 0, sizeof(info));
603 ok(pFDSA_Initialize(block_size, inc, &info, mem, init_blocks), "FDSA_Initialize rets FALSE\n");
604 ok(info.num_items == 0, "num_items = %d\n", info.num_items);
605 ok(info.mem == mem, "mem = %p\n", info.mem);
606 ok(info.blocks_alloced == init_blocks, "blocks_alloced = %d\n", info.blocks_alloced);
607 ok(info.inc == inc, "inc = %d\n", info.inc);
608 ok(info.block_size == block_size, "block_size = %d\n", info.block_size);
609 ok(info.flags == 0, "flags = %d\n", info.flags);
611 ret = pFDSA_InsertItem(&info, 1234, "1234567890");
612 ok(ret == 0, "ret = %d\n", ret);
613 ok(info.num_items == 1, "num_items = %d\n", info.num_items);
614 ok(info.mem == mem, "mem = %p\n", info.mem);
615 ok(info.blocks_alloced == init_blocks, "blocks_alloced = %d\n", info.blocks_alloced);
616 ok(info.inc == inc, "inc = %d\n", info.inc);
617 ok(info.block_size == block_size, "block_size = %d\n", info.block_size);
618 ok(info.flags == 0, "flags = %d\n", info.flags);
620 ret = pFDSA_InsertItem(&info, 1234, "abcdefghij");
621 ok(ret == 1, "ret = %d\n", ret);
623 ret = pFDSA_InsertItem(&info, 1, "klmnopqrst");
624 ok(ret == 1, "ret = %d\n", ret);
626 ret = pFDSA_InsertItem(&info, 0, "uvwxyzABCD");
627 ok(ret == 0, "ret = %d\n", ret);
628 ok(info.mem == mem, "mem = %p\n", info.mem);
629 ok(info.flags == 0, "flags = %d\n", info.flags);
631 /* This next InsertItem will cause shlwapi to allocate its own mem buffer */
632 ret = pFDSA_InsertItem(&info, 0, "EFGHIJKLMN");
633 ok(ret == 0, "ret = %d\n", ret);
634 ok(info.mem != mem, "mem = %p\n", info.mem);
635 ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %d\n", info.blocks_alloced);
636 ok(info.flags == 0x1, "flags = %d\n", info.flags);
638 ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCD1234567890klmnopqrstabcdefghij", 50), "mem %s\n", (char*)info.mem);
640 ok(pFDSA_DeleteItem(&info, 2), "rets FALSE\n");
641 ok(info.mem != mem, "mem = %p\n", info.mem);
642 ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %d\n", info.blocks_alloced);
643 ok(info.flags == 0x1, "flags = %d\n", info.flags);
645 ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCDklmnopqrstabcdefghij", 40), "mem %s\n", (char*)info.mem);
647 ok(pFDSA_DeleteItem(&info, 3), "rets FALSE\n");
648 ok(info.mem != mem, "mem = %p\n", info.mem);
649 ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %d\n", info.blocks_alloced);
650 ok(info.flags == 0x1, "flags = %d\n", info.flags);
652 ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCDklmnopqrst", 30), "mem %s\n", (char*)info.mem);
654 ok(!pFDSA_DeleteItem(&info, 4), "does not ret FALSE\n");
656 /* As shlwapi has allocated memory internally, Destroy will ret FALSE */
657 ok(!pFDSA_Destroy(&info), "FDSA_Destroy does not ret FALSE\n");
660 /* When Initialize is called with inc = 0, set it to 1 */
661 ok(pFDSA_Initialize(block_size, 0, &info, mem, init_blocks), "FDSA_Initialize rets FALSE\n");
662 ok(info.inc == 1, "inc = %d\n", info.inc);
664 /* This time, because shlwapi hasn't had to allocate memory
665 internally, Destroy rets non-zero */
666 ok(pFDSA_Destroy(&info), "FDSA_Destroy rets FALSE\n");
669 HeapFree(GetProcessHeap(), 0, mem);
673 typedef struct SHELL_USER_SID {
674 SID_IDENTIFIER_AUTHORITY sidAuthority;
675 DWORD dwUserGroupID;
676 DWORD dwUserID;
677 } SHELL_USER_SID, *PSHELL_USER_SID;
678 typedef struct SHELL_USER_PERMISSION {
679 SHELL_USER_SID susID;
680 DWORD dwAccessType;
681 BOOL fInherit;
682 DWORD dwAccessMask;
683 DWORD dwInheritMask;
684 DWORD dwInheritAccessMask;
685 } SHELL_USER_PERMISSION, *PSHELL_USER_PERMISSION;
686 static void test_GetShellSecurityDescriptor(void)
688 SHELL_USER_PERMISSION supCurrentUserFull = {
689 { {SECURITY_NULL_SID_AUTHORITY}, 0, 0 },
690 ACCESS_ALLOWED_ACE_TYPE, FALSE,
691 GENERIC_ALL, 0, 0 };
692 #define MY_INHERITANCE 0xBE /* invalid value to proof behavior */
693 SHELL_USER_PERMISSION supEveryoneDenied = {
694 { {SECURITY_WORLD_SID_AUTHORITY}, SECURITY_WORLD_RID, 0 },
695 ACCESS_DENIED_ACE_TYPE, TRUE,
696 GENERIC_WRITE, MY_INHERITANCE | 0xDEADBA00, GENERIC_READ };
697 PSHELL_USER_PERMISSION rgsup[2] = {
698 &supCurrentUserFull, &supEveryoneDenied,
700 SECURITY_DESCRIPTOR* psd;
701 SECURITY_DESCRIPTOR* (WINAPI*pGetShellSecurityDescriptor)(PSHELL_USER_PERMISSION*,int);
702 void *pChrCmpIW = GetProcAddress(hShlwapi, "ChrCmpIW");
704 pGetShellSecurityDescriptor=(void*)GetProcAddress(hShlwapi,(char*)475);
706 if(!pGetShellSecurityDescriptor)
708 win_skip("GetShellSecurityDescriptor not available\n");
709 return;
712 if(pChrCmpIW && pChrCmpIW == pGetShellSecurityDescriptor) /* win2k */
714 win_skip("Skipping for GetShellSecurityDescriptor, same ordinal used for ChrCmpIW\n");
715 return;
718 psd = pGetShellSecurityDescriptor(NULL, 2);
719 ok(psd==NULL ||
720 broken(psd==INVALID_HANDLE_VALUE), /* IE5 */
721 "GetShellSecurityDescriptor should fail\n");
722 psd = pGetShellSecurityDescriptor(rgsup, 0);
723 ok(psd==NULL, "GetShellSecurityDescriptor should fail, got %p\n", psd);
725 SetLastError(0xdeadbeef);
726 psd = pGetShellSecurityDescriptor(rgsup, 2);
727 if (psd == NULL && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
729 /* The previous calls to GetShellSecurityDescriptor don't set the last error */
730 win_skip("GetShellSecurityDescriptor is not implemented\n");
731 return;
733 if (psd == INVALID_HANDLE_VALUE)
735 win_skip("GetShellSecurityDescriptor is broken on IE5\n");
736 return;
738 ok(psd!=NULL, "GetShellSecurityDescriptor failed\n");
739 if (psd!=NULL)
741 BOOL bHasDacl = FALSE, bDefaulted, ret;
742 PACL pAcl;
743 DWORD dwRev;
744 SECURITY_DESCRIPTOR_CONTROL control;
746 ok(IsValidSecurityDescriptor(psd), "returned value is not valid SD\n");
748 ret = GetSecurityDescriptorControl(psd, &control, &dwRev);
749 ok(ret, "GetSecurityDescriptorControl failed with error %u\n", GetLastError());
750 ok(0 == (control & SE_SELF_RELATIVE), "SD should be absolute\n");
752 ret = GetSecurityDescriptorDacl(psd, &bHasDacl, &pAcl, &bDefaulted);
753 ok(ret, "GetSecurityDescriptorDacl failed with error %u\n", GetLastError());
755 ok(bHasDacl, "SD has no DACL\n");
756 if (bHasDacl)
758 ok(!bDefaulted, "DACL should not be defaulted\n");
760 ok(pAcl != NULL, "NULL DACL!\n");
761 if (pAcl != NULL)
763 ACL_SIZE_INFORMATION asiSize;
765 ok(IsValidAcl(pAcl), "DACL is not valid\n");
767 ret = GetAclInformation(pAcl, &asiSize, sizeof(asiSize), AclSizeInformation);
768 ok(ret, "GetAclInformation failed with error %u\n", GetLastError());
770 ok(asiSize.AceCount == 3, "Incorrect number of ACEs: %d entries\n", asiSize.AceCount);
771 if (asiSize.AceCount == 3)
773 ACCESS_ALLOWED_ACE *paaa; /* will use for DENIED too */
775 ret = GetAce(pAcl, 0, (LPVOID*)&paaa);
776 ok(ret, "GetAce failed with error %u\n", GetLastError());
777 ok(paaa->Header.AceType == ACCESS_ALLOWED_ACE_TYPE,
778 "Invalid ACE type %d\n", paaa->Header.AceType);
779 ok(paaa->Header.AceFlags == 0, "Invalid ACE flags %x\n", paaa->Header.AceFlags);
780 ok(paaa->Mask == GENERIC_ALL, "Invalid ACE mask %x\n", paaa->Mask);
782 ret = GetAce(pAcl, 1, (LPVOID*)&paaa);
783 ok(ret, "GetAce failed with error %u\n", GetLastError());
784 ok(paaa->Header.AceType == ACCESS_DENIED_ACE_TYPE,
785 "Invalid ACE type %d\n", paaa->Header.AceType);
786 /* first one of two ACEs generated from inheritable entry - without inheritance */
787 ok(paaa->Header.AceFlags == 0, "Invalid ACE flags %x\n", paaa->Header.AceFlags);
788 ok(paaa->Mask == GENERIC_WRITE, "Invalid ACE mask %x\n", paaa->Mask);
790 ret = GetAce(pAcl, 2, (LPVOID*)&paaa);
791 ok(ret, "GetAce failed with error %u\n", GetLastError());
792 ok(paaa->Header.AceType == ACCESS_DENIED_ACE_TYPE,
793 "Invalid ACE type %d\n", paaa->Header.AceType);
794 /* second ACE - with inheritance */
795 ok(paaa->Header.AceFlags == MY_INHERITANCE,
796 "Invalid ACE flags %x\n", paaa->Header.AceFlags);
797 ok(paaa->Mask == GENERIC_READ, "Invalid ACE mask %x\n", paaa->Mask);
802 LocalFree(psd);
806 static void test_SHPackDispParams(void)
808 DISPPARAMS params;
809 VARIANT vars[10];
810 HRESULT hres;
812 if(!pSHPackDispParams)
813 win_skip("SHPackSidpParams not available\n");
815 memset(&params, 0xc0, sizeof(params));
816 memset(vars, 0xc0, sizeof(vars));
817 hres = pSHPackDispParams(&params, vars, 1, VT_I4, 0xdeadbeef);
818 ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres);
819 ok(params.cArgs == 1, "params.cArgs = %d\n", params.cArgs);
820 ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
821 ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
822 ok(params.rgvarg == vars, "params.rgvarg = %p\n", params.rgvarg);
823 ok(V_VT(vars) == VT_I4, "V_VT(var) = %d\n", V_VT(vars));
824 ok(V_I4(vars) == 0xdeadbeef, "failed %x\n", V_I4(vars));
826 memset(&params, 0xc0, sizeof(params));
827 hres = pSHPackDispParams(&params, NULL, 0, 0);
828 ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres);
829 ok(params.cArgs == 0, "params.cArgs = %d\n", params.cArgs);
830 ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
831 ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
832 ok(params.rgvarg == NULL, "params.rgvarg = %p\n", params.rgvarg);
834 memset(vars, 0xc0, sizeof(vars));
835 memset(&params, 0xc0, sizeof(params));
836 hres = pSHPackDispParams(&params, vars, 4, VT_BSTR, (void*)0xdeadbeef, VT_EMPTY, 10,
837 VT_I4, 100, VT_DISPATCH, (void*)0xdeadbeef);
838 ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres);
839 ok(params.cArgs == 4, "params.cArgs = %d\n", params.cArgs);
840 ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
841 ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
842 ok(params.rgvarg == vars, "params.rgvarg = %p\n", params.rgvarg);
843 ok(V_VT(vars) == VT_DISPATCH, "V_VT(vars[0]) = %x\n", V_VT(vars));
844 ok(V_I4(vars) == 0xdeadbeef, "V_I4(vars[0]) = %x\n", V_I4(vars));
845 ok(V_VT(vars+1) == VT_I4, "V_VT(vars[1]) = %d\n", V_VT(vars+1));
846 ok(V_I4(vars+1) == 100, "V_I4(vars[1]) = %x\n", V_I4(vars+1));
847 ok(V_VT(vars+2) == VT_I4, "V_VT(vars[2]) = %d\n", V_VT(vars+2));
848 ok(V_I4(vars+2) == 10, "V_I4(vars[2]) = %x\n", V_I4(vars+2));
849 ok(V_VT(vars+3) == VT_BSTR, "V_VT(vars[3]) = %d\n", V_VT(vars+3));
850 ok(V_BSTR(vars+3) == (void*)0xdeadbeef, "V_BSTR(vars[3]) = %p\n", V_BSTR(vars+3));
853 typedef struct _disp
855 IDispatch IDispatch_iface;
856 LONG refCount;
857 } Disp;
859 static inline Disp *impl_from_IDispatch(IDispatch *iface)
861 return CONTAINING_RECORD(iface, Disp, IDispatch_iface);
864 typedef struct _contain
866 IConnectionPointContainer IConnectionPointContainer_iface;
867 LONG refCount;
869 UINT ptCount;
870 IConnectionPoint **pt;
871 } Contain;
873 static inline Contain *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
875 return CONTAINING_RECORD(iface, Contain, IConnectionPointContainer_iface);
878 typedef struct _cntptn
880 IConnectionPoint IConnectionPoint_iface;
881 LONG refCount;
883 Contain *container;
884 GUID id;
885 UINT sinkCount;
886 IUnknown **sink;
887 } ConPt;
889 static inline ConPt *impl_from_IConnectionPoint(IConnectionPoint *iface)
891 return CONTAINING_RECORD(iface, ConPt, IConnectionPoint_iface);
894 typedef struct _enum
896 IEnumConnections IEnumConnections_iface;
897 LONG refCount;
899 UINT idx;
900 ConPt *pt;
901 } EnumCon;
903 static inline EnumCon *impl_from_IEnumConnections(IEnumConnections *iface)
905 return CONTAINING_RECORD(iface, EnumCon, IEnumConnections_iface);
908 typedef struct _enumpt
910 IEnumConnectionPoints IEnumConnectionPoints_iface;
911 LONG refCount;
913 int idx;
914 Contain *container;
915 } EnumPt;
917 static inline EnumPt *impl_from_IEnumConnectionPoints(IEnumConnectionPoints *iface)
919 return CONTAINING_RECORD(iface, EnumPt, IEnumConnectionPoints_iface);
923 static HRESULT WINAPI Disp_QueryInterface(
924 IDispatch* This,
925 REFIID riid,
926 void **ppvObject)
928 *ppvObject = NULL;
930 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDispatch))
932 *ppvObject = This;
935 if (*ppvObject)
937 IDispatch_AddRef(This);
938 return S_OK;
941 trace("no interface\n");
942 return E_NOINTERFACE;
945 static ULONG WINAPI Disp_AddRef(IDispatch* This)
947 Disp *iface = impl_from_IDispatch(This);
948 return InterlockedIncrement(&iface->refCount);
951 static ULONG WINAPI Disp_Release(IDispatch* This)
953 Disp *iface = impl_from_IDispatch(This);
954 ULONG ret;
956 ret = InterlockedDecrement(&iface->refCount);
957 if (ret == 0)
958 HeapFree(GetProcessHeap(),0,This);
959 return ret;
962 static HRESULT WINAPI Disp_GetTypeInfoCount(
963 IDispatch* This,
964 UINT *pctinfo)
966 return ERROR_SUCCESS;
969 static HRESULT WINAPI Disp_GetTypeInfo(
970 IDispatch* This,
971 UINT iTInfo,
972 LCID lcid,
973 ITypeInfo **ppTInfo)
975 return ERROR_SUCCESS;
978 static HRESULT WINAPI Disp_GetIDsOfNames(
979 IDispatch* This,
980 REFIID riid,
981 LPOLESTR *rgszNames,
982 UINT cNames,
983 LCID lcid,
984 DISPID *rgDispId)
986 return ERROR_SUCCESS;
989 static HRESULT WINAPI Disp_Invoke(
990 IDispatch* This,
991 DISPID dispIdMember,
992 REFIID riid,
993 LCID lcid,
994 WORD wFlags,
995 DISPPARAMS *pDispParams,
996 VARIANT *pVarResult,
997 EXCEPINFO *pExcepInfo,
998 UINT *puArgErr)
1000 trace("%p %x %p %x %x %p %p %p %p\n",This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
1002 ok(dispIdMember == 0xa0 || dispIdMember == 0xa1, "Unknown dispIdMember\n");
1003 ok(pDispParams != NULL, "Invoked with NULL pDispParams\n");
1004 ok(wFlags == DISPATCH_METHOD, "Wrong flags %x\n",wFlags);
1005 ok(lcid == 0,"Wrong lcid %x\n",lcid);
1006 if (dispIdMember == 0xa0)
1008 ok(pDispParams->cArgs == 0, "params.cArgs = %d\n", pDispParams->cArgs);
1009 ok(pDispParams->cNamedArgs == 0, "params.cNamedArgs = %d\n", pDispParams->cArgs);
1010 ok(pDispParams->rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", pDispParams->rgdispidNamedArgs);
1011 ok(pDispParams->rgvarg == NULL, "params.rgvarg = %p\n", pDispParams->rgvarg);
1013 else if (dispIdMember == 0xa1)
1015 ok(pDispParams->cArgs == 2, "params.cArgs = %d\n", pDispParams->cArgs);
1016 ok(pDispParams->cNamedArgs == 0, "params.cNamedArgs = %d\n", pDispParams->cArgs);
1017 ok(pDispParams->rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", pDispParams->rgdispidNamedArgs);
1018 ok(V_VT(pDispParams->rgvarg) == VT_BSTR, "V_VT(var) = %d\n", V_VT(pDispParams->rgvarg));
1019 ok(V_I4(pDispParams->rgvarg) == 0xdeadcafe , "failed %p\n", V_BSTR(pDispParams->rgvarg));
1020 ok(V_VT(pDispParams->rgvarg+1) == VT_I4, "V_VT(var) = %d\n", V_VT(pDispParams->rgvarg+1));
1021 ok(V_I4(pDispParams->rgvarg+1) == 0xdeadbeef, "failed %x\n", V_I4(pDispParams->rgvarg+1));
1024 return ERROR_SUCCESS;
1027 static const IDispatchVtbl disp_vtbl = {
1028 Disp_QueryInterface,
1029 Disp_AddRef,
1030 Disp_Release,
1032 Disp_GetTypeInfoCount,
1033 Disp_GetTypeInfo,
1034 Disp_GetIDsOfNames,
1035 Disp_Invoke
1038 static HRESULT WINAPI Enum_QueryInterface(
1039 IEnumConnections* This,
1040 REFIID riid,
1041 void **ppvObject)
1043 *ppvObject = NULL;
1045 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumConnections))
1047 *ppvObject = This;
1050 if (*ppvObject)
1052 IEnumConnections_AddRef(This);
1053 return S_OK;
1056 trace("no interface\n");
1057 return E_NOINTERFACE;
1060 static ULONG WINAPI Enum_AddRef(IEnumConnections* This)
1062 EnumCon *iface = impl_from_IEnumConnections(This);
1063 return InterlockedIncrement(&iface->refCount);
1066 static ULONG WINAPI Enum_Release(IEnumConnections* This)
1068 EnumCon *iface = impl_from_IEnumConnections(This);
1069 ULONG ret;
1071 ret = InterlockedDecrement(&iface->refCount);
1072 if (ret == 0)
1073 HeapFree(GetProcessHeap(),0,This);
1074 return ret;
1077 static HRESULT WINAPI Enum_Next(
1078 IEnumConnections* This,
1079 ULONG cConnections,
1080 LPCONNECTDATA rgcd,
1081 ULONG *pcFetched)
1083 EnumCon *iface = impl_from_IEnumConnections(This);
1085 if (cConnections > 0 && iface->idx < iface->pt->sinkCount)
1087 rgcd->pUnk = iface->pt->sink[iface->idx];
1088 IUnknown_AddRef(iface->pt->sink[iface->idx]);
1089 rgcd->dwCookie=0xff;
1090 if (pcFetched)
1091 *pcFetched = 1;
1092 iface->idx++;
1093 return S_OK;
1096 return E_FAIL;
1099 static HRESULT WINAPI Enum_Skip(
1100 IEnumConnections* This,
1101 ULONG cConnections)
1103 return E_FAIL;
1106 static HRESULT WINAPI Enum_Reset(
1107 IEnumConnections* This)
1109 return E_FAIL;
1112 static HRESULT WINAPI Enum_Clone(
1113 IEnumConnections* This,
1114 IEnumConnections **ppEnum)
1116 return E_FAIL;
1119 static const IEnumConnectionsVtbl enum_vtbl = {
1121 Enum_QueryInterface,
1122 Enum_AddRef,
1123 Enum_Release,
1124 Enum_Next,
1125 Enum_Skip,
1126 Enum_Reset,
1127 Enum_Clone
1130 static HRESULT WINAPI ConPt_QueryInterface(
1131 IConnectionPoint* This,
1132 REFIID riid,
1133 void **ppvObject)
1135 *ppvObject = NULL;
1137 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IConnectionPoint))
1139 *ppvObject = This;
1142 if (*ppvObject)
1144 IConnectionPoint_AddRef(This);
1145 return S_OK;
1148 trace("no interface\n");
1149 return E_NOINTERFACE;
1152 static ULONG WINAPI ConPt_AddRef(
1153 IConnectionPoint* This)
1155 ConPt *iface = impl_from_IConnectionPoint(This);
1156 return InterlockedIncrement(&iface->refCount);
1159 static ULONG WINAPI ConPt_Release(
1160 IConnectionPoint* This)
1162 ConPt *iface = impl_from_IConnectionPoint(This);
1163 ULONG ret;
1165 ret = InterlockedDecrement(&iface->refCount);
1166 if (ret == 0)
1168 if (iface->sinkCount > 0)
1170 int i;
1171 for (i = 0; i < iface->sinkCount; i++)
1173 if (iface->sink[i])
1174 IUnknown_Release(iface->sink[i]);
1176 HeapFree(GetProcessHeap(),0,iface->sink);
1178 HeapFree(GetProcessHeap(),0,This);
1180 return ret;
1183 static HRESULT WINAPI ConPt_GetConnectionInterface(
1184 IConnectionPoint* This,
1185 IID *pIID)
1187 static int i = 0;
1188 ConPt *iface = impl_from_IConnectionPoint(This);
1189 if (i==0)
1191 i++;
1192 return E_FAIL;
1194 else
1195 memcpy(pIID,&iface->id,sizeof(GUID));
1196 return S_OK;
1199 static HRESULT WINAPI ConPt_GetConnectionPointContainer(
1200 IConnectionPoint* This,
1201 IConnectionPointContainer **ppCPC)
1203 ConPt *iface = impl_from_IConnectionPoint(This);
1205 *ppCPC = &iface->container->IConnectionPointContainer_iface;
1206 return S_OK;
1209 static HRESULT WINAPI ConPt_Advise(
1210 IConnectionPoint* This,
1211 IUnknown *pUnkSink,
1212 DWORD *pdwCookie)
1214 ConPt *iface = impl_from_IConnectionPoint(This);
1216 if (iface->sinkCount == 0)
1217 iface->sink = HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown*));
1218 else
1219 iface->sink = HeapReAlloc(GetProcessHeap(),0,iface->sink,sizeof(IUnknown*)*(iface->sinkCount+1));
1220 iface->sink[iface->sinkCount] = pUnkSink;
1221 IUnknown_AddRef(pUnkSink);
1222 iface->sinkCount++;
1223 *pdwCookie = iface->sinkCount;
1224 return S_OK;
1227 static HRESULT WINAPI ConPt_Unadvise(
1228 IConnectionPoint* This,
1229 DWORD dwCookie)
1231 ConPt *iface = impl_from_IConnectionPoint(This);
1233 if (dwCookie > iface->sinkCount)
1234 return E_FAIL;
1235 else
1237 IUnknown_Release(iface->sink[dwCookie-1]);
1238 iface->sink[dwCookie-1] = NULL;
1240 return S_OK;
1243 static HRESULT WINAPI ConPt_EnumConnections(
1244 IConnectionPoint* This,
1245 IEnumConnections **ppEnum)
1247 EnumCon *ec;
1249 ec = HeapAlloc(GetProcessHeap(),0,sizeof(EnumCon));
1250 ec->IEnumConnections_iface.lpVtbl = &enum_vtbl;
1251 ec->refCount = 1;
1252 ec->pt = impl_from_IConnectionPoint(This);
1253 ec->idx = 0;
1254 *ppEnum = &ec->IEnumConnections_iface;
1256 return S_OK;
1259 static const IConnectionPointVtbl point_vtbl = {
1260 ConPt_QueryInterface,
1261 ConPt_AddRef,
1262 ConPt_Release,
1264 ConPt_GetConnectionInterface,
1265 ConPt_GetConnectionPointContainer,
1266 ConPt_Advise,
1267 ConPt_Unadvise,
1268 ConPt_EnumConnections
1271 static HRESULT WINAPI EnumPt_QueryInterface(
1272 IEnumConnectionPoints* This,
1273 REFIID riid,
1274 void **ppvObject)
1276 *ppvObject = NULL;
1278 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumConnectionPoints))
1280 *ppvObject = This;
1283 if (*ppvObject)
1285 IEnumConnectionPoints_AddRef(This);
1286 return S_OK;
1289 trace("no interface\n");
1290 return E_NOINTERFACE;
1293 static ULONG WINAPI EnumPt_AddRef(IEnumConnectionPoints* This)
1295 EnumPt *iface = impl_from_IEnumConnectionPoints(This);
1296 return InterlockedIncrement(&iface->refCount);
1299 static ULONG WINAPI EnumPt_Release(IEnumConnectionPoints* This)
1301 EnumPt *iface = impl_from_IEnumConnectionPoints(This);
1302 ULONG ret;
1304 ret = InterlockedDecrement(&iface->refCount);
1305 if (ret == 0)
1306 HeapFree(GetProcessHeap(),0,This);
1307 return ret;
1310 static HRESULT WINAPI EnumPt_Next(
1311 IEnumConnectionPoints* This,
1312 ULONG cConnections,
1313 IConnectionPoint **rgcd,
1314 ULONG *pcFetched)
1316 EnumPt *iface = impl_from_IEnumConnectionPoints(This);
1318 if (cConnections > 0 && iface->idx < iface->container->ptCount)
1320 *rgcd = iface->container->pt[iface->idx];
1321 IConnectionPoint_AddRef(iface->container->pt[iface->idx]);
1322 if (pcFetched)
1323 *pcFetched = 1;
1324 iface->idx++;
1325 return S_OK;
1328 return E_FAIL;
1331 static HRESULT WINAPI EnumPt_Skip(
1332 IEnumConnectionPoints* This,
1333 ULONG cConnections)
1335 return E_FAIL;
1338 static HRESULT WINAPI EnumPt_Reset(
1339 IEnumConnectionPoints* This)
1341 return E_FAIL;
1344 static HRESULT WINAPI EnumPt_Clone(
1345 IEnumConnectionPoints* This,
1346 IEnumConnectionPoints **ppEnumPt)
1348 return E_FAIL;
1351 static const IEnumConnectionPointsVtbl enumpt_vtbl = {
1353 EnumPt_QueryInterface,
1354 EnumPt_AddRef,
1355 EnumPt_Release,
1356 EnumPt_Next,
1357 EnumPt_Skip,
1358 EnumPt_Reset,
1359 EnumPt_Clone
1362 static HRESULT WINAPI Contain_QueryInterface(
1363 IConnectionPointContainer* This,
1364 REFIID riid,
1365 void **ppvObject)
1367 *ppvObject = NULL;
1369 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IConnectionPointContainer))
1371 *ppvObject = This;
1374 if (*ppvObject)
1376 IConnectionPointContainer_AddRef(This);
1377 return S_OK;
1380 trace("no interface\n");
1381 return E_NOINTERFACE;
1384 static ULONG WINAPI Contain_AddRef(
1385 IConnectionPointContainer* This)
1387 Contain *iface = impl_from_IConnectionPointContainer(This);
1388 return InterlockedIncrement(&iface->refCount);
1391 static ULONG WINAPI Contain_Release(
1392 IConnectionPointContainer* This)
1394 Contain *iface = impl_from_IConnectionPointContainer(This);
1395 ULONG ret;
1397 ret = InterlockedDecrement(&iface->refCount);
1398 if (ret == 0)
1400 if (iface->ptCount > 0)
1402 int i;
1403 for (i = 0; i < iface->ptCount; i++)
1404 IConnectionPoint_Release(iface->pt[i]);
1405 HeapFree(GetProcessHeap(),0,iface->pt);
1407 HeapFree(GetProcessHeap(),0,This);
1409 return ret;
1412 static HRESULT WINAPI Contain_EnumConnectionPoints(
1413 IConnectionPointContainer* This,
1414 IEnumConnectionPoints **ppEnum)
1416 EnumPt *ec;
1418 ec = HeapAlloc(GetProcessHeap(),0,sizeof(EnumPt));
1419 ec->IEnumConnectionPoints_iface.lpVtbl = &enumpt_vtbl;
1420 ec->refCount = 1;
1421 ec->idx= 0;
1422 ec->container = impl_from_IConnectionPointContainer(This);
1423 *ppEnum = &ec->IEnumConnectionPoints_iface;
1425 return S_OK;
1428 static HRESULT WINAPI Contain_FindConnectionPoint(
1429 IConnectionPointContainer* This,
1430 REFIID riid,
1431 IConnectionPoint **ppCP)
1433 Contain *iface = impl_from_IConnectionPointContainer(This);
1434 ConPt *pt;
1436 if (!IsEqualIID(riid, &IID_NULL) || iface->ptCount ==0)
1438 pt = HeapAlloc(GetProcessHeap(),0,sizeof(ConPt));
1439 pt->IConnectionPoint_iface.lpVtbl = &point_vtbl;
1440 pt->refCount = 1;
1441 pt->sinkCount = 0;
1442 pt->sink = NULL;
1443 pt->container = iface;
1444 pt->id = IID_IDispatch;
1446 if (iface->ptCount == 0)
1447 iface->pt =HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown*));
1448 else
1449 iface->pt = HeapReAlloc(GetProcessHeap(),0,iface->pt,sizeof(IUnknown*)*(iface->ptCount+1));
1450 iface->pt[iface->ptCount] = &pt->IConnectionPoint_iface;
1451 iface->ptCount++;
1453 *ppCP = &pt->IConnectionPoint_iface;
1455 else
1457 *ppCP = iface->pt[0];
1458 IUnknown_AddRef((IUnknown*)*ppCP);
1461 return S_OK;
1464 static const IConnectionPointContainerVtbl contain_vtbl = {
1465 Contain_QueryInterface,
1466 Contain_AddRef,
1467 Contain_Release,
1469 Contain_EnumConnectionPoints,
1470 Contain_FindConnectionPoint
1473 static void test_IConnectionPoint(void)
1475 HRESULT rc;
1476 ULONG ref;
1477 IConnectionPoint *point;
1478 Contain *container;
1479 Disp *dispatch;
1480 DWORD cookie = 0xffffffff;
1481 DISPPARAMS params;
1482 VARIANT vars[10];
1484 if (!pIConnectionPoint_SimpleInvoke || !pConnectToConnectionPoint)
1486 win_skip("IConnectionPoint Apis not present\n");
1487 return;
1490 container = HeapAlloc(GetProcessHeap(),0,sizeof(Contain));
1491 container->IConnectionPointContainer_iface.lpVtbl = &contain_vtbl;
1492 container->refCount = 1;
1493 container->ptCount = 0;
1494 container->pt = NULL;
1496 dispatch = HeapAlloc(GetProcessHeap(),0,sizeof(Disp));
1497 dispatch->IDispatch_iface.lpVtbl = &disp_vtbl;
1498 dispatch->refCount = 1;
1500 rc = pConnectToConnectionPoint((IUnknown*)dispatch, &IID_NULL, TRUE, (IUnknown*)container, &cookie, &point);
1501 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1502 ok(point != NULL, "returned ConnectionPoint is NULL\n");
1503 ok(cookie != 0xffffffff, "invalid cookie returned\n");
1505 rc = pIConnectionPoint_SimpleInvoke(point,0xa0,NULL);
1506 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1508 if (pSHPackDispParams)
1510 memset(&params, 0xc0, sizeof(params));
1511 memset(vars, 0xc0, sizeof(vars));
1512 rc = pSHPackDispParams(&params, vars, 2, VT_I4, 0xdeadbeef, VT_BSTR, 0xdeadcafe);
1513 ok(rc == S_OK, "SHPackDispParams failed: %08x\n", rc);
1515 rc = pIConnectionPoint_SimpleInvoke(point,0xa1,&params);
1516 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1518 else
1519 win_skip("pSHPackDispParams not present\n");
1521 rc = pConnectToConnectionPoint(NULL, &IID_NULL, FALSE, (IUnknown*)container, &cookie, NULL);
1522 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1524 /* MSDN says this should be required but it crashs on XP
1525 IUnknown_Release(point);
1527 ref = IUnknown_Release((IUnknown*)container);
1528 ok(ref == 0, "leftover IConnectionPointContainer reference %i\n",ref);
1529 ref = IUnknown_Release((IUnknown*)dispatch);
1530 ok(ref == 0, "leftover IDispatch reference %i\n",ref);
1533 typedef struct _propbag
1535 IPropertyBag IPropertyBag_iface;
1536 LONG refCount;
1538 } PropBag;
1540 static inline PropBag *impl_from_IPropertyBag(IPropertyBag *iface)
1542 return CONTAINING_RECORD(iface, PropBag, IPropertyBag_iface);
1546 static HRESULT WINAPI Prop_QueryInterface(
1547 IPropertyBag* This,
1548 REFIID riid,
1549 void **ppvObject)
1551 *ppvObject = NULL;
1553 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPropertyBag))
1555 *ppvObject = This;
1558 if (*ppvObject)
1560 IPropertyBag_AddRef(This);
1561 return S_OK;
1564 trace("no interface\n");
1565 return E_NOINTERFACE;
1568 static ULONG WINAPI Prop_AddRef(
1569 IPropertyBag* This)
1571 PropBag *iface = impl_from_IPropertyBag(This);
1572 return InterlockedIncrement(&iface->refCount);
1575 static ULONG WINAPI Prop_Release(
1576 IPropertyBag* This)
1578 PropBag *iface = impl_from_IPropertyBag(This);
1579 ULONG ret;
1581 ret = InterlockedDecrement(&iface->refCount);
1582 if (ret == 0)
1583 HeapFree(GetProcessHeap(),0,This);
1584 return ret;
1587 static HRESULT WINAPI Prop_Read(
1588 IPropertyBag* This,
1589 LPCOLESTR pszPropName,
1590 VARIANT *pVar,
1591 IErrorLog *pErrorLog)
1593 V_VT(pVar) = VT_BLOB|VT_BYREF;
1594 V_BYREF(pVar) = (LPVOID)0xdeadcafe;
1595 return S_OK;
1598 static HRESULT WINAPI Prop_Write(
1599 IPropertyBag* This,
1600 LPCOLESTR pszPropName,
1601 VARIANT *pVar)
1603 return S_OK;
1607 static const IPropertyBagVtbl prop_vtbl = {
1608 Prop_QueryInterface,
1609 Prop_AddRef,
1610 Prop_Release,
1612 Prop_Read,
1613 Prop_Write
1616 static void test_SHPropertyBag_ReadLONG(void)
1618 PropBag *pb;
1619 HRESULT rc;
1620 LONG out;
1621 static const WCHAR szName1[] = {'n','a','m','e','1',0};
1623 if (!pSHPropertyBag_ReadLONG)
1625 win_skip("SHPropertyBag_ReadLONG not present\n");
1626 return;
1629 pb = HeapAlloc(GetProcessHeap(),0,sizeof(PropBag));
1630 pb->refCount = 1;
1631 pb->IPropertyBag_iface.lpVtbl = &prop_vtbl;
1633 out = 0xfeedface;
1634 rc = pSHPropertyBag_ReadLONG(NULL, szName1, &out);
1635 ok(rc == E_INVALIDARG || broken(rc == 0), "incorrect return %x\n",rc);
1636 ok(out == 0xfeedface, "value should not have changed\n");
1637 rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, NULL, &out);
1638 ok(rc == E_INVALIDARG || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
1639 ok(out == 0xfeedface, "value should not have changed\n");
1640 rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, szName1, NULL);
1641 ok(rc == E_INVALIDARG || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
1642 rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, szName1, &out);
1643 ok(rc == DISP_E_BADVARTYPE || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
1644 ok(out == 0xfeedface || broken(out == 0xfeedfa00), "value should not have changed %x\n",out);
1645 IUnknown_Release((IUnknown*)pb);
1650 static void test_SHSetWindowBits(void)
1652 HWND hwnd;
1653 DWORD style, styleold;
1654 WNDCLASSA clsA;
1656 if(!pSHSetWindowBits)
1658 win_skip("SHSetWindowBits is not available\n");
1659 return;
1662 clsA.style = 0;
1663 clsA.lpfnWndProc = DefWindowProcA;
1664 clsA.cbClsExtra = 0;
1665 clsA.cbWndExtra = 0;
1666 clsA.hInstance = GetModuleHandleA(NULL);
1667 clsA.hIcon = 0;
1668 clsA.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
1669 clsA.hbrBackground = NULL;
1670 clsA.lpszMenuName = NULL;
1671 clsA.lpszClassName = "Shlwapi test class";
1672 RegisterClassA(&clsA);
1674 hwnd = CreateWindowA("Shlwapi test class", "Test", WS_VISIBLE, 0, 0, 100, 100,
1675 NULL, NULL, GetModuleHandleA(NULL), 0);
1676 ok(IsWindow(hwnd), "failed to create window\n");
1678 /* null window */
1679 SetLastError(0xdeadbeef);
1680 style = pSHSetWindowBits(NULL, GWL_STYLE, 0, 0);
1681 ok(style == 0, "expected 0 retval, got %d\n", style);
1682 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
1683 broken(GetLastError() == 0xdeadbeef), /* Win9x/WinMe */
1684 "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
1686 /* zero mask, zero flags */
1687 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1688 style = pSHSetWindowBits(hwnd, GWL_STYLE, 0, 0);
1689 ok(styleold == style, "expected old style\n");
1690 ok(styleold == GetWindowLongA(hwnd, GWL_STYLE), "expected to keep old style\n");
1692 /* test mask */
1693 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1694 ok(styleold & WS_VISIBLE, "expected WS_VISIBLE\n");
1695 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1697 ok(style == styleold, "expected previous style, got %x\n", style);
1698 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1700 /* test mask, unset style bit used */
1701 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1702 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1703 ok(style == styleold, "expected previous style, got %x\n", style);
1704 ok(styleold == GetWindowLongA(hwnd, GWL_STYLE), "expected to keep old style\n");
1706 /* set back with flags */
1707 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1708 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, WS_VISIBLE);
1709 ok(style == styleold, "expected previous style, got %x\n", style);
1710 ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "expected updated style\n");
1712 /* reset and try to set without a mask */
1713 pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1714 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1715 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1716 style = pSHSetWindowBits(hwnd, GWL_STYLE, 0, WS_VISIBLE);
1717 ok(style == styleold, "expected previous style, got %x\n", style);
1718 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1720 DestroyWindow(hwnd);
1722 UnregisterClassA("Shlwapi test class", GetModuleHandleA(NULL));
1725 static void test_SHFormatDateTimeA(void)
1727 FILETIME UNALIGNED filetime;
1728 CHAR buff[100], buff2[100], buff3[100];
1729 SYSTEMTIME st;
1730 DWORD flags;
1731 INT ret;
1733 if(!pSHFormatDateTimeA)
1735 win_skip("pSHFormatDateTimeA isn't available\n");
1736 return;
1739 if (0)
1741 /* crashes on native */
1742 pSHFormatDateTimeA(NULL, NULL, NULL, 0);
1745 GetLocalTime(&st);
1746 SystemTimeToFileTime(&st, &filetime);
1747 /* SHFormatDateTime expects input as utc */
1748 LocalFileTimeToFileTime(&filetime, &filetime);
1750 /* no way to get required buffer length here */
1751 SetLastError(0xdeadbeef);
1752 ret = pSHFormatDateTimeA(&filetime, NULL, NULL, 0);
1753 ok(ret == 0, "got %d\n", ret);
1754 ok(GetLastError() == 0xdeadbeef || broken(GetLastError() == ERROR_SUCCESS /* Win7 */),
1755 "expected 0xdeadbeef, got %d\n", GetLastError());
1757 SetLastError(0xdeadbeef);
1758 buff[0] = 'a'; buff[1] = 0;
1759 ret = pSHFormatDateTimeA(&filetime, NULL, buff, 0);
1760 ok(ret == 0, "got %d\n", ret);
1761 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1762 ok(buff[0] == 'a', "expected same string, got %s\n", buff);
1764 /* flags needs to have FDTF_NOAUTOREADINGORDER for these tests to succeed on Vista+ */
1766 /* all combinations documented as invalid succeeded */
1767 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTTIME | FDTF_LONGTIME;
1768 SetLastError(0xdeadbeef);
1769 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1770 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1771 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1773 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_LONGDATE;
1774 SetLastError(0xdeadbeef);
1775 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1776 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1777 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1779 flags = FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE;
1780 SetLastError(0xdeadbeef);
1781 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1782 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1783 ok(GetLastError() == 0xdeadbeef ||
1784 broken(GetLastError() == ERROR_INVALID_FLAGS), /* Win9x/WinMe */
1785 "expected 0xdeadbeef, got %d\n", GetLastError());
1787 /* now check returned strings */
1788 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTTIME;
1789 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1790 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1791 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff2, sizeof(buff2));
1792 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1793 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1795 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGTIME;
1796 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1797 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1798 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2));
1799 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1800 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1802 /* both time flags */
1803 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGTIME | FDTF_SHORTTIME;
1804 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1805 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1806 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2));
1807 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1808 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1810 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE;
1811 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1812 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1813 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1814 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1815 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1817 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE;
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_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1821 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1822 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1824 /* both date flags */
1825 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_SHORTDATE;
1826 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1827 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1828 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1829 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1830 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1832 /* various combinations of date/time flags */
1833 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_SHORTTIME;
1834 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1835 ok(ret == lstrlenA(buff)+1, "got %d, length %d\n", ret, lstrlenA(buff)+1);
1836 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3));
1837 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1838 ok(lstrcmpA(buff3, buff + lstrlenA(buff) - lstrlenA(buff3)) == 0,
1839 "expected (%s), got (%s) for time part\n",
1840 buff3, buff + lstrlenA(buff) - lstrlenA(buff3));
1841 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1842 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1843 buff[lstrlenA(buff2)] = '\0';
1844 ok(lstrcmpA(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1845 buff2, buff);
1847 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_LONGTIME;
1848 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1849 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1850 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3));
1851 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1852 ok(lstrcmpA(buff3, buff + lstrlenA(buff) - lstrlenA(buff3)) == 0,
1853 "expected (%s), got (%s) for time part\n",
1854 buff3, buff + lstrlenA(buff) - lstrlenA(buff3));
1855 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1856 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1857 buff[lstrlenA(buff2)] = '\0';
1858 ok(lstrcmpA(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1859 buff2, buff);
1861 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_SHORTTIME;
1862 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1863 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1864 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1865 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1866 strcat(buff2, " ");
1867 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3));
1868 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1869 strcat(buff2, buff3);
1870 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1872 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_LONGTIME;
1873 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1874 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1875 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1876 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1877 strcat(buff2, " ");
1878 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3));
1879 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1880 strcat(buff2, buff3);
1881 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1884 static void test_SHFormatDateTimeW(void)
1886 FILETIME UNALIGNED filetime;
1887 WCHAR buff[100], buff2[100], buff3[100], *p1, *p2;
1888 SYSTEMTIME st;
1889 DWORD flags;
1890 INT ret;
1891 static const WCHAR spaceW[] = {' ',0};
1892 #define UNICODE_LTR_MARK 0x200e
1893 #define UNICODE_RTL_MARK 0x200f
1895 if(!pSHFormatDateTimeW)
1897 win_skip("pSHFormatDateTimeW isn't available\n");
1898 return;
1901 if (0)
1903 /* crashes on native */
1904 pSHFormatDateTimeW(NULL, NULL, NULL, 0);
1907 GetLocalTime(&st);
1908 SystemTimeToFileTime(&st, &filetime);
1909 /* SHFormatDateTime expects input as utc */
1910 LocalFileTimeToFileTime(&filetime, &filetime);
1912 /* no way to get required buffer length here */
1913 SetLastError(0xdeadbeef);
1914 ret = pSHFormatDateTimeW(&filetime, NULL, NULL, 0);
1915 ok(ret == 0, "expected 0, got %d\n", ret);
1916 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1918 SetLastError(0xdeadbeef);
1919 buff[0] = 'a'; buff[1] = 0;
1920 ret = pSHFormatDateTimeW(&filetime, NULL, buff, 0);
1921 ok(ret == 0, "expected 0, got %d\n", ret);
1922 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1923 ok(buff[0] == 'a', "expected same string\n");
1925 /* all combinations documented as invalid succeeded */
1926 flags = FDTF_SHORTTIME | FDTF_LONGTIME;
1927 SetLastError(0xdeadbeef);
1928 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1929 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1930 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1931 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1933 flags = FDTF_SHORTDATE | FDTF_LONGDATE;
1934 SetLastError(0xdeadbeef);
1935 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1936 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1937 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1938 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1940 flags = FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE;
1941 SetLastError(0xdeadbeef);
1942 buff[0] = 0; /* NT4 doesn't clear the buffer on failure */
1943 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1944 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1945 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1946 ok(GetLastError() == 0xdeadbeef ||
1947 broken(GetLastError() == ERROR_INVALID_FLAGS), /* Win9x/WinMe/NT4 */
1948 "expected 0xdeadbeef, got %d\n", GetLastError());
1950 /* now check returned strings */
1951 flags = FDTF_SHORTTIME;
1952 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1953 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1954 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1955 SetLastError(0xdeadbeef);
1956 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1957 if (ret == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1959 win_skip("Needed W-functions are not implemented\n");
1960 return;
1962 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1963 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1965 flags = FDTF_LONGTIME;
1966 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1967 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1968 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1969 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1970 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1971 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1973 /* both time flags */
1974 flags = FDTF_LONGTIME | FDTF_SHORTTIME;
1975 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1976 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1977 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1978 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1979 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1980 ok(lstrcmpW(buff, buff2) == 0, "expected equal string\n");
1982 flags = FDTF_SHORTDATE;
1983 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1984 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1985 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1986 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1987 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1988 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1990 flags = FDTF_LONGDATE;
1991 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1992 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1993 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1994 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1995 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1996 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1998 /* both date flags */
1999 flags = FDTF_LONGDATE | FDTF_SHORTDATE;
2000 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
2001 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
2002 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
2003 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
2004 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
2005 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
2007 /* various combinations of date/time flags */
2008 flags = FDTF_LONGDATE | FDTF_SHORTTIME;
2009 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
2010 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
2011 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
2012 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
2013 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
2014 ok(lstrcmpW(buff3, buff + lstrlenW(buff) - lstrlenW(buff3)) == 0,
2015 "expected (%s), got (%s) for time part\n",
2016 wine_dbgstr_w(buff3), wine_dbgstr_w(buff + lstrlenW(buff) - lstrlenW(buff3)));
2017 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
2018 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
2019 p1 = buff;
2020 p2 = buff2;
2021 while (*p2 != '\0')
2023 while (*p1 == UNICODE_LTR_MARK || *p1 == UNICODE_RTL_MARK)
2024 p1++;
2025 while (*p2 == UNICODE_LTR_MARK || *p2 == UNICODE_RTL_MARK)
2026 p2++;
2027 p1++;
2028 p2++;
2030 *p1 = '\0';
2031 ok(lstrcmpW(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
2032 wine_dbgstr_w(buff2), wine_dbgstr_w(buff));
2034 flags = FDTF_LONGDATE | FDTF_LONGTIME;
2035 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
2036 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
2037 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
2038 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
2039 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
2040 ok(lstrcmpW(buff3, buff + lstrlenW(buff) - lstrlenW(buff3)) == 0,
2041 "expected (%s), got (%s) for time part\n",
2042 wine_dbgstr_w(buff3), wine_dbgstr_w(buff + lstrlenW(buff) - lstrlenW(buff3)));
2043 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
2044 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
2045 p1 = buff;
2046 p2 = buff2;
2047 while (*p2 != '\0')
2049 while (*p1 == UNICODE_LTR_MARK || *p1 == UNICODE_RTL_MARK)
2050 p1++;
2051 while (*p2 == UNICODE_LTR_MARK || *p2 == UNICODE_RTL_MARK)
2052 p2++;
2053 p1++;
2054 p2++;
2056 *p1 = '\0';
2057 ok(lstrcmpW(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
2058 wine_dbgstr_w(buff2), wine_dbgstr_w(buff));
2060 flags = FDTF_SHORTDATE | FDTF_SHORTTIME;
2061 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
2062 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
2063 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
2064 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
2065 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
2066 lstrcatW(buff2, spaceW);
2067 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
2068 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
2069 lstrcatW(buff2, buff3);
2070 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
2072 flags = FDTF_SHORTDATE | FDTF_LONGTIME;
2073 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
2074 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
2075 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
2076 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
2077 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
2078 lstrcatW(buff2, spaceW);
2079 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
2080 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
2081 lstrcatW(buff2, buff3);
2082 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
2085 static void test_SHGetObjectCompatFlags(void)
2087 struct compat_value {
2088 CHAR nameA[30];
2089 DWORD value;
2092 struct compat_value values[] = {
2093 { "OTNEEDSSFCACHE", 0x1 },
2094 { "NO_WEBVIEW", 0x2 },
2095 { "UNBINDABLE", 0x4 },
2096 { "PINDLL", 0x8 },
2097 { "NEEDSFILESYSANCESTOR", 0x10 },
2098 { "NOTAFILESYSTEM", 0x20 },
2099 { "CTXMENU_NOVERBS", 0x40 },
2100 { "CTXMENU_LIMITEDQI", 0x80 },
2101 { "COCREATESHELLFOLDERONLY", 0x100 },
2102 { "NEEDSSTORAGEANCESTOR", 0x200 },
2103 { "NOLEGACYWEBVIEW", 0x400 },
2104 { "CTXMENU_XPQCMFLAGS", 0x1000 },
2105 { "NOIPROPERTYSTORE", 0x2000 }
2108 static const char compat_path[] = "Software\\Microsoft\\Windows\\CurrentVersion\\ShellCompatibility\\Objects";
2109 void *pColorAdjustLuma = GetProcAddress(hShlwapi, "ColorAdjustLuma");
2110 CHAR keyA[39]; /* {CLSID} */
2111 HKEY root;
2112 DWORD ret;
2113 int i;
2115 if (!pSHGetObjectCompatFlags)
2117 win_skip("SHGetObjectCompatFlags isn't available\n");
2118 return;
2121 if (pColorAdjustLuma && pColorAdjustLuma == pSHGetObjectCompatFlags) /* win2k */
2123 win_skip("Skipping SHGetObjectCompatFlags, same ordinal used for ColorAdjustLuma\n");
2124 return;
2127 /* null args */
2128 ret = pSHGetObjectCompatFlags(NULL, NULL);
2129 ok(ret == 0, "got %d\n", ret);
2131 ret = RegOpenKeyA(HKEY_LOCAL_MACHINE, compat_path, &root);
2132 if (ret != ERROR_SUCCESS)
2134 skip("No compatibility class data found\n");
2135 return;
2138 for (i = 0; RegEnumKeyA(root, i, keyA, sizeof(keyA)) == ERROR_SUCCESS; i++)
2140 HKEY clsid_key;
2142 if (RegOpenKeyA(root, keyA, &clsid_key) == ERROR_SUCCESS)
2144 CHAR valueA[30];
2145 DWORD expected = 0, got, length = sizeof(valueA);
2146 CLSID clsid;
2147 int v;
2149 for (v = 0; RegEnumValueA(clsid_key, v, valueA, &length, NULL, NULL, NULL, NULL) == ERROR_SUCCESS; v++)
2151 int j;
2153 for (j = 0; j < sizeof(values)/sizeof(struct compat_value); j++)
2154 if (lstrcmpA(values[j].nameA, valueA) == 0)
2156 expected |= values[j].value;
2157 break;
2160 length = sizeof(valueA);
2163 pGUIDFromStringA(keyA, &clsid);
2164 got = pSHGetObjectCompatFlags(NULL, &clsid);
2165 ok(got == expected, "got 0x%08x, expected 0x%08x. Key %s\n", got, expected, keyA);
2167 RegCloseKey(clsid_key);
2171 RegCloseKey(root);
2174 typedef struct {
2175 IOleCommandTarget IOleCommandTarget_iface;
2176 LONG ref;
2177 } IOleCommandTargetImpl;
2179 static inline IOleCommandTargetImpl *impl_from_IOleCommandTarget(IOleCommandTarget *iface)
2181 return CONTAINING_RECORD(iface, IOleCommandTargetImpl, IOleCommandTarget_iface);
2184 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl;
2186 static IOleCommandTarget* IOleCommandTargetImpl_Construct(void)
2188 IOleCommandTargetImpl *obj;
2190 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2191 obj->IOleCommandTarget_iface.lpVtbl = &IOleCommandTargetImpl_Vtbl;
2192 obj->ref = 1;
2194 return &obj->IOleCommandTarget_iface;
2197 static HRESULT WINAPI IOleCommandTargetImpl_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppvObj)
2199 IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface);
2201 if (IsEqualIID(riid, &IID_IUnknown) ||
2202 IsEqualIID(riid, &IID_IOleCommandTarget))
2204 *ppvObj = This;
2207 if(*ppvObj)
2209 IOleCommandTarget_AddRef(iface);
2210 return S_OK;
2213 return E_NOINTERFACE;
2216 static ULONG WINAPI IOleCommandTargetImpl_AddRef(IOleCommandTarget *iface)
2218 IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface);
2219 return InterlockedIncrement(&This->ref);
2222 static ULONG WINAPI IOleCommandTargetImpl_Release(IOleCommandTarget *iface)
2224 IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface);
2225 ULONG ref = InterlockedDecrement(&This->ref);
2227 if (!ref)
2229 HeapFree(GetProcessHeap(), 0, This);
2230 return 0;
2232 return ref;
2235 static HRESULT WINAPI IOleCommandTargetImpl_QueryStatus(
2236 IOleCommandTarget *iface, const GUID *group, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText)
2238 return E_NOTIMPL;
2241 static HRESULT WINAPI IOleCommandTargetImpl_Exec(
2242 IOleCommandTarget *iface,
2243 const GUID *CmdGroup,
2244 DWORD nCmdID,
2245 DWORD nCmdexecopt,
2246 VARIANT *pvaIn,
2247 VARIANT *pvaOut)
2249 add_call(&trace_got, 3, CmdGroup, (void*)(DWORD_PTR)nCmdID, (void*)(DWORD_PTR)nCmdexecopt, pvaIn, pvaOut);
2250 return S_OK;
2253 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl =
2255 IOleCommandTargetImpl_QueryInterface,
2256 IOleCommandTargetImpl_AddRef,
2257 IOleCommandTargetImpl_Release,
2258 IOleCommandTargetImpl_QueryStatus,
2259 IOleCommandTargetImpl_Exec
2262 typedef struct {
2263 IServiceProvider IServiceProvider_iface;
2264 LONG ref;
2265 } IServiceProviderImpl;
2267 static inline IServiceProviderImpl *impl_from_IServiceProvider(IServiceProvider *iface)
2269 return CONTAINING_RECORD(iface, IServiceProviderImpl, IServiceProvider_iface);
2272 typedef struct {
2273 IProfferService IProfferService_iface;
2274 LONG ref;
2275 } IProfferServiceImpl;
2277 static inline IProfferServiceImpl *impl_from_IProfferService(IProfferService *iface)
2279 return CONTAINING_RECORD(iface, IProfferServiceImpl, IProfferService_iface);
2283 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl;
2284 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl;
2286 static IServiceProvider* IServiceProviderImpl_Construct(void)
2288 IServiceProviderImpl *obj;
2290 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2291 obj->IServiceProvider_iface.lpVtbl = &IServiceProviderImpl_Vtbl;
2292 obj->ref = 1;
2294 return &obj->IServiceProvider_iface;
2297 static IProfferService* IProfferServiceImpl_Construct(void)
2299 IProfferServiceImpl *obj;
2301 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2302 obj->IProfferService_iface.lpVtbl = &IProfferServiceImpl_Vtbl;
2303 obj->ref = 1;
2305 return &obj->IProfferService_iface;
2308 static HRESULT WINAPI IServiceProviderImpl_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppvObj)
2310 IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
2312 if (IsEqualIID(riid, &IID_IUnknown) ||
2313 IsEqualIID(riid, &IID_IServiceProvider))
2315 *ppvObj = This;
2318 if(*ppvObj)
2320 IServiceProvider_AddRef(iface);
2321 /* native uses redefined IID_IServiceProvider symbol, so we can't compare pointers */
2322 if (IsEqualIID(riid, &IID_IServiceProvider))
2323 add_call(&trace_got, 1, iface, &IID_IServiceProvider, 0, 0, 0);
2324 return S_OK;
2327 return E_NOINTERFACE;
2330 static ULONG WINAPI IServiceProviderImpl_AddRef(IServiceProvider *iface)
2332 IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
2333 return InterlockedIncrement(&This->ref);
2336 static ULONG WINAPI IServiceProviderImpl_Release(IServiceProvider *iface)
2338 IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
2339 ULONG ref = InterlockedDecrement(&This->ref);
2341 if (!ref)
2343 HeapFree(GetProcessHeap(), 0, This);
2344 return 0;
2346 return ref;
2349 static HRESULT WINAPI IServiceProviderImpl_QueryService(
2350 IServiceProvider *iface, REFGUID service, REFIID riid, void **ppv)
2352 /* native uses redefined pointer for IID_IOleCommandTarget, not one from uuid.lib */
2353 if (IsEqualIID(riid, &IID_IOleCommandTarget))
2355 add_call(&trace_got, 2, iface, service, &IID_IOleCommandTarget, 0, 0);
2356 *ppv = IOleCommandTargetImpl_Construct();
2358 if (IsEqualIID(riid, &IID_IProfferService))
2360 if (IsEqualIID(service, &IID_IProfferService))
2361 add_call(&trace_got, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2362 *ppv = IProfferServiceImpl_Construct();
2364 return S_OK;
2367 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl =
2369 IServiceProviderImpl_QueryInterface,
2370 IServiceProviderImpl_AddRef,
2371 IServiceProviderImpl_Release,
2372 IServiceProviderImpl_QueryService
2375 static void test_IUnknown_QueryServiceExec(void)
2377 IServiceProvider *provider;
2378 static const GUID dummy_serviceid = { 0xdeadbeef };
2379 static const GUID dummy_groupid = { 0xbeefbeef };
2380 call_trace_t trace_expected;
2381 HRESULT hr;
2383 /* on <=W2K platforms same ordinal used for another export with different
2384 prototype, so skipping using this indirect condition */
2385 if (is_win2k_and_lower)
2387 win_skip("IUnknown_QueryServiceExec is not available\n");
2388 return;
2391 provider = IServiceProviderImpl_Construct();
2393 /* null source pointer */
2394 hr = pIUnknown_QueryServiceExec(NULL, &dummy_serviceid, &dummy_groupid, 0, 0, 0, 0);
2395 ok(hr == E_FAIL ||
2396 hr == E_NOTIMPL, /* win 8 */
2397 "got 0x%08x\n", hr);
2399 /* expected trace:
2400 IUnknown_QueryServiceExec( ptr1, serviceid, groupid, arg1, arg2, arg3, arg4);
2401 -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &prov );
2402 -> IServiceProvider_QueryService( prov, serviceid, &IID_IOleCommandTarget, &obj );
2403 -> IOleCommandTarget_Exec( obj, groupid, arg1, arg2, arg3, arg4 );
2405 init_call_trace(&trace_expected);
2407 add_call(&trace_expected, 1, provider, &IID_IServiceProvider, 0, 0, 0);
2408 add_call(&trace_expected, 2, provider, &dummy_serviceid, &IID_IOleCommandTarget, 0, 0);
2409 add_call(&trace_expected, 3, &dummy_groupid, (void*)0x1, (void*)0x2, (void*)0x3, (void*)0x4);
2411 init_call_trace(&trace_got);
2412 hr = pIUnknown_QueryServiceExec((IUnknown*)provider, &dummy_serviceid, &dummy_groupid, 0x1, 0x2, (void*)0x3, (void*)0x4);
2413 ok(hr == S_OK, "got 0x%08x\n", hr);
2415 ok_trace(&trace_expected, &trace_got);
2417 free_call_trace(&trace_expected);
2418 free_call_trace(&trace_got);
2420 IServiceProvider_Release(provider);
2424 static HRESULT WINAPI IProfferServiceImpl_QueryInterface(IProfferService *iface, REFIID riid, void **ppvObj)
2426 IProfferServiceImpl *This = impl_from_IProfferService(iface);
2428 if (IsEqualIID(riid, &IID_IUnknown) ||
2429 IsEqualIID(riid, &IID_IProfferService))
2431 *ppvObj = This;
2433 else if (IsEqualIID(riid, &IID_IServiceProvider))
2435 *ppvObj = IServiceProviderImpl_Construct();
2436 add_call(&trace_got, 1, iface, &IID_IServiceProvider, 0, 0, 0);
2437 return S_OK;
2440 if(*ppvObj)
2442 IProfferService_AddRef(iface);
2443 return S_OK;
2446 return E_NOINTERFACE;
2449 static ULONG WINAPI IProfferServiceImpl_AddRef(IProfferService *iface)
2451 IProfferServiceImpl *This = impl_from_IProfferService(iface);
2452 return InterlockedIncrement(&This->ref);
2455 static ULONG WINAPI IProfferServiceImpl_Release(IProfferService *iface)
2457 IProfferServiceImpl *This = impl_from_IProfferService(iface);
2458 ULONG ref = InterlockedDecrement(&This->ref);
2460 if (!ref)
2462 HeapFree(GetProcessHeap(), 0, This);
2463 return 0;
2465 return ref;
2468 static HRESULT WINAPI IProfferServiceImpl_ProfferService(IProfferService *iface,
2469 REFGUID service, IServiceProvider *pService, DWORD *pCookie)
2471 *pCookie = 0xdeadbeef;
2472 add_call(&trace_got, 3, service, pService, pCookie, 0, 0);
2473 return S_OK;
2476 static HRESULT WINAPI IProfferServiceImpl_RevokeService(IProfferService *iface, DWORD cookie)
2478 add_call(&trace_got, 4, (void*)(DWORD_PTR)cookie, 0, 0, 0, 0);
2479 return S_OK;
2482 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl =
2484 IProfferServiceImpl_QueryInterface,
2485 IProfferServiceImpl_AddRef,
2486 IProfferServiceImpl_Release,
2487 IProfferServiceImpl_ProfferService,
2488 IProfferServiceImpl_RevokeService
2491 static void test_IUnknown_ProfferService(void)
2493 IServiceProvider *provider;
2494 IProfferService *proff;
2495 static const GUID dummy_serviceid = { 0xdeadbeef };
2496 call_trace_t trace_expected;
2497 HRESULT hr;
2498 DWORD cookie;
2500 /* on <=W2K platforms same ordinal used for another export with different
2501 prototype, so skipping using this indirect condition */
2502 if (is_win2k_and_lower)
2504 win_skip("IUnknown_ProfferService is not available\n");
2505 return;
2508 provider = IServiceProviderImpl_Construct();
2509 proff = IProfferServiceImpl_Construct();
2511 /* null source pointer */
2512 hr = pIUnknown_ProfferService(NULL, &dummy_serviceid, 0, 0);
2513 ok(hr == E_FAIL ||
2514 hr == E_NOTIMPL, /* win 8 */
2515 "got 0x%08x\n", hr);
2517 /* expected trace:
2518 IUnknown_ProfferService( ptr1, serviceid, arg1, arg2);
2519 -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &provider );
2520 -> IServiceProvider_QueryService( provider, &IID_IProfferService, &IID_IProfferService, &proffer );
2522 if (service pointer not null):
2523 -> IProfferService_ProfferService( proffer, serviceid, arg1, arg2 );
2524 else
2525 -> IProfferService_RevokeService( proffer, *arg2 );
2527 init_call_trace(&trace_expected);
2529 add_call(&trace_expected, 1, proff, &IID_IServiceProvider, 0, 0, 0);
2530 add_call(&trace_expected, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2531 add_call(&trace_expected, 3, &dummy_serviceid, provider, &cookie, 0, 0);
2533 init_call_trace(&trace_got);
2534 cookie = 0;
2535 hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, provider, &cookie);
2536 ok(hr == S_OK, "got 0x%08x\n", hr);
2537 ok(cookie == 0xdeadbeef, "got %x\n", cookie);
2539 ok_trace(&trace_expected, &trace_got);
2540 free_call_trace(&trace_got);
2541 free_call_trace(&trace_expected);
2543 /* same with ::Revoke path */
2544 init_call_trace(&trace_expected);
2546 add_call(&trace_expected, 1, proff, &IID_IServiceProvider, 0, 0, 0);
2547 add_call(&trace_expected, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2548 add_call(&trace_expected, 4, (void*)(DWORD_PTR)cookie, 0, 0, 0, 0);
2550 init_call_trace(&trace_got);
2551 ok(cookie != 0, "got %x\n", cookie);
2552 hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, 0, &cookie);
2553 ok(hr == S_OK, "got 0x%08x\n", hr);
2554 ok(cookie == 0, "got %x\n", cookie);
2555 ok_trace(&trace_expected, &trace_got);
2556 free_call_trace(&trace_got);
2557 free_call_trace(&trace_expected);
2559 IServiceProvider_Release(provider);
2560 IProfferService_Release(proff);
2563 static void test_SHCreateWorkerWindowA(void)
2565 WNDCLASSA cliA;
2566 char classA[20];
2567 HWND hwnd;
2568 LONG_PTR ret;
2569 BOOL res;
2571 if (is_win2k_and_lower)
2573 win_skip("SHCreateWorkerWindowA not available\n");
2574 return;
2577 hwnd = pSHCreateWorkerWindowA(0, NULL, 0, 0, 0, 0);
2578 ok(hwnd != 0, "expected window\n");
2580 GetClassNameA(hwnd, classA, 20);
2581 ok(lstrcmpA(classA, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA);
2583 ret = GetWindowLongPtrA(hwnd, 0);
2584 ok(ret == 0, "got %ld\n", ret);
2586 /* class info */
2587 memset(&cliA, 0, sizeof(cliA));
2588 res = GetClassInfoA(GetModuleHandleA("shlwapi.dll"), "WorkerA", &cliA);
2589 ok(res, "failed to get class info\n");
2590 ok(cliA.style == 0, "got 0x%08x\n", cliA.style);
2591 ok(cliA.cbClsExtra == 0, "got %d\n", cliA.cbClsExtra);
2592 ok(cliA.cbWndExtra == sizeof(LONG_PTR), "got %d\n", cliA.cbWndExtra);
2593 ok(cliA.lpszMenuName == 0, "got %s\n", cliA.lpszMenuName);
2595 DestroyWindow(hwnd);
2597 /* set extra bytes */
2598 hwnd = pSHCreateWorkerWindowA(0, NULL, 0, 0, 0, 0xdeadbeef);
2599 ok(hwnd != 0, "expected window\n");
2601 GetClassNameA(hwnd, classA, 20);
2602 ok(lstrcmpA(classA, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA);
2604 ret = GetWindowLongPtrA(hwnd, 0);
2605 ok(ret == 0xdeadbeef, "got %ld\n", ret);
2607 /* test exstyle */
2608 ret = GetWindowLongA(hwnd, GWL_EXSTYLE);
2609 ok(ret == WS_EX_WINDOWEDGE ||
2610 ret == (WS_EX_WINDOWEDGE|WS_EX_LAYOUTRTL) /* systems with RTL locale */, "0x%08lx\n", ret);
2612 DestroyWindow(hwnd);
2614 hwnd = pSHCreateWorkerWindowA(0, NULL, WS_EX_TOOLWINDOW, 0, 0, 0);
2615 ret = GetWindowLongA(hwnd, GWL_EXSTYLE);
2616 ok(ret == (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW) ||
2617 ret == (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW|WS_EX_LAYOUTRTL) /* systems with RTL locale */, "0x%08lx\n", ret);
2618 DestroyWindow(hwnd);
2621 static HRESULT WINAPI SF_QueryInterface(IShellFolder *iface,
2622 REFIID riid, void **ppv)
2624 /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */
2625 ok(!IsEqualGUID(&IID_IShellFolder, riid),
2626 "Unexpected QI for IShellFolder\n");
2627 return E_NOINTERFACE;
2630 static ULONG WINAPI SF_AddRef(IShellFolder *iface)
2632 return 2;
2635 static ULONG WINAPI SF_Release(IShellFolder *iface)
2637 return 1;
2640 static HRESULT WINAPI SF_ParseDisplayName(IShellFolder *iface,
2641 HWND owner, LPBC reserved, LPOLESTR displayName, ULONG *eaten,
2642 LPITEMIDLIST *idl, ULONG *attr)
2644 ok(0, "Didn't expect ParseDisplayName\n");
2645 return E_NOTIMPL;
2648 static HRESULT WINAPI SF_EnumObjects(IShellFolder *iface,
2649 HWND owner, SHCONTF flags, IEnumIDList **enm)
2651 *enm = (IEnumIDList*)0xcafebabe;
2652 return S_OK;
2655 static HRESULT WINAPI SF_BindToObject(IShellFolder *iface,
2656 LPCITEMIDLIST idl, LPBC reserved, REFIID riid, void **obj)
2658 ok(0, "Didn't expect BindToObject\n");
2659 return E_NOTIMPL;
2662 static HRESULT WINAPI SF_BindToStorage(IShellFolder *iface,
2663 LPCITEMIDLIST idl, LPBC reserved, REFIID riid, void **obj)
2665 ok(0, "Didn't expect BindToStorage\n");
2666 return E_NOTIMPL;
2669 static HRESULT WINAPI SF_CompareIDs(IShellFolder *iface,
2670 LPARAM lparam, LPCITEMIDLIST idl1, LPCITEMIDLIST idl2)
2672 ok(0, "Didn't expect CompareIDs\n");
2673 return E_NOTIMPL;
2676 static HRESULT WINAPI SF_CreateViewObject(IShellFolder *iface,
2677 HWND owner, REFIID riid, void **out)
2679 ok(0, "Didn't expect CreateViewObject\n");
2680 return E_NOTIMPL;
2683 static HRESULT WINAPI SF_GetAttributesOf(IShellFolder *iface,
2684 UINT cidl, LPCITEMIDLIST *idl, SFGAOF *inOut)
2686 ok(0, "Didn't expect GetAttributesOf\n");
2687 return E_NOTIMPL;
2690 static HRESULT WINAPI SF_GetUIObjectOf(IShellFolder *iface,
2691 HWND owner, UINT cidl, LPCITEMIDLIST *idls, REFIID riid, UINT *inOut,
2692 void **out)
2694 ok(0, "Didn't expect GetUIObjectOf\n");
2695 return E_NOTIMPL;
2698 static HRESULT WINAPI SF_GetDisplayNameOf(IShellFolder *iface,
2699 LPCITEMIDLIST idl, SHGDNF flags, STRRET *name)
2701 ok(0, "Didn't expect GetDisplayNameOf\n");
2702 return E_NOTIMPL;
2705 static HRESULT WINAPI SF_SetNameOf(IShellFolder *iface,
2706 HWND hwnd, LPCITEMIDLIST idl, LPCOLESTR name, SHGDNF flags,
2707 LPITEMIDLIST *idlOut)
2709 ok(0, "Didn't expect SetNameOf\n");
2710 return E_NOTIMPL;
2713 static IShellFolderVtbl ShellFolderVtbl = {
2714 SF_QueryInterface,
2715 SF_AddRef,
2716 SF_Release,
2717 SF_ParseDisplayName,
2718 SF_EnumObjects,
2719 SF_BindToObject,
2720 SF_BindToStorage,
2721 SF_CompareIDs,
2722 SF_CreateViewObject,
2723 SF_GetAttributesOf,
2724 SF_GetUIObjectOf,
2725 SF_GetDisplayNameOf,
2726 SF_SetNameOf
2729 static IShellFolder ShellFolder = { &ShellFolderVtbl };
2731 static void test_SHIShellFolder_EnumObjects(void)
2733 IEnumIDList *enm;
2734 HRESULT hres;
2735 IShellFolder *folder;
2737 if(!pSHIShellFolder_EnumObjects || is_win2k_and_lower){
2738 win_skip("SHIShellFolder_EnumObjects not available\n");
2739 return;
2742 if(0){
2743 /* NULL object crashes on Windows */
2744 pSHIShellFolder_EnumObjects(NULL, NULL, 0, NULL);
2747 /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */
2748 enm = (IEnumIDList*)0xdeadbeef;
2749 hres = pSHIShellFolder_EnumObjects(&ShellFolder, NULL, 0, &enm);
2750 ok(hres == S_OK, "SHIShellFolder_EnumObjects failed: 0x%08x\n", hres);
2751 ok(enm == (IEnumIDList*)0xcafebabe, "Didn't get expected enumerator location, instead: %p\n", enm);
2753 /* SHIShellFolder_EnumObjects isn't strict about the IShellFolder object */
2754 hres = pSHGetDesktopFolder(&folder);
2755 ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
2757 enm = NULL;
2758 hres = pSHIShellFolder_EnumObjects(folder, NULL, 0, &enm);
2759 ok(hres == S_OK, "SHIShellFolder_EnumObjects failed: 0x%08x\n", hres);
2760 ok(enm != NULL, "Didn't get an enumerator\n");
2761 if(enm)
2762 IEnumIDList_Release(enm);
2764 IShellFolder_Release(folder);
2767 static BOOL write_inifile(LPCWSTR filename)
2769 DWORD written;
2770 HANDLE file;
2772 static const char data[] =
2773 "[TestApp]\r\n"
2774 "AKey=1\r\n"
2775 "AnotherKey=asdf\r\n";
2777 file = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
2778 if(file == INVALID_HANDLE_VALUE) {
2779 win_skip("failed to create ini file at %s\n", wine_dbgstr_w(filename));
2780 return FALSE;
2783 WriteFile(file, data, sizeof(data), &written, NULL);
2785 CloseHandle(file);
2787 return TRUE;
2790 #define verify_inifile(f, e) r_verify_inifile(__LINE__, f, e)
2791 static void r_verify_inifile(unsigned l, LPCWSTR filename, LPCSTR exp)
2793 HANDLE file;
2794 CHAR buf[1024];
2795 DWORD read;
2797 file = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
2799 if(file == INVALID_HANDLE_VALUE)
2800 return;
2802 ReadFile(file, buf, sizeof(buf) * sizeof(CHAR), &read, NULL);
2803 buf[read] = '\0';
2805 CloseHandle(file);
2807 ok_(__FILE__,l)(!strcmp(buf, exp), "Expected:\n%s\nGot:\n%s\n", exp,
2808 buf);
2811 static void test_SHGetIniString(void)
2813 DWORD ret;
2814 WCHAR out[64] = {0};
2816 static const WCHAR TestAppW[] = {'T','e','s','t','A','p','p',0};
2817 static const WCHAR AKeyW[] = {'A','K','e','y',0};
2818 static const WCHAR AnotherKeyW[] = {'A','n','o','t','h','e','r','K','e','y',0};
2819 static const WCHAR JunkKeyW[] = {'J','u','n','k','K','e','y',0};
2820 static const WCHAR testpathW[] = {'C',':','\\','t','e','s','t','.','i','n','i',0};
2821 WCHAR pathW[MAX_PATH];
2823 if(!pSHGetIniStringW || is_win2k_and_lower){
2824 win_skip("SHGetIniStringW is not available\n");
2825 return;
2828 lstrcpyW(pathW, testpathW);
2830 if (!write_inifile(pathW))
2831 return;
2833 if(0){
2834 /* these crash on Windows */
2835 pSHGetIniStringW(NULL, NULL, NULL, 0, NULL);
2836 pSHGetIniStringW(NULL, AKeyW, out, sizeof(out), pathW);
2837 pSHGetIniStringW(TestAppW, AKeyW, NULL, sizeof(out), pathW);
2840 ret = pSHGetIniStringW(TestAppW, AKeyW, out, 0, pathW);
2841 ok(ret == 0, "SHGetIniStringW should have given 0, instead: %d\n", ret);
2843 /* valid arguments */
2844 out[0] = 0;
2845 SetLastError(0xdeadbeef);
2846 ret = pSHGetIniStringW(TestAppW, NULL, out, sizeof(out), pathW);
2847 ok(ret == 4, "SHGetIniStringW should have given 4, instead: %d\n", ret);
2848 ok(!lstrcmpW(out, AKeyW), "Expected %s, got: %s, %d\n",
2849 wine_dbgstr_w(AKeyW), wine_dbgstr_w(out), GetLastError());
2851 ret = pSHGetIniStringW(TestAppW, AKeyW, out, sizeof(out), pathW);
2852 ok(ret == 1, "SHGetIniStringW should have given 1, instead: %d\n", ret);
2853 ok(!strcmp_wa(out, "1"), "Expected L\"1\", got: %s\n", wine_dbgstr_w(out));
2855 ret = pSHGetIniStringW(TestAppW, AnotherKeyW, out, sizeof(out), pathW);
2856 ok(ret == 4, "SHGetIniStringW should have given 4, instead: %d\n", ret);
2857 ok(!strcmp_wa(out, "asdf"), "Expected L\"asdf\", got: %s\n", wine_dbgstr_w(out));
2859 out[0] = 1;
2860 ret = pSHGetIniStringW(TestAppW, JunkKeyW, out, sizeof(out), pathW);
2861 ok(ret == 0, "SHGetIniStringW should have given 0, instead: %d\n", ret);
2862 ok(*out == 0, "Expected L\"\", got: %s\n", wine_dbgstr_w(out));
2864 DeleteFileW(pathW);
2867 static void test_SHSetIniString(void)
2869 BOOL ret;
2871 static const WCHAR TestAppW[] = {'T','e','s','t','A','p','p',0};
2872 static const WCHAR AnotherAppW[] = {'A','n','o','t','h','e','r','A','p','p',0};
2873 static const WCHAR TestIniW[] = {'C',':','\\','t','e','s','t','.','i','n','i',0};
2874 static const WCHAR AKeyW[] = {'A','K','e','y',0};
2875 static const WCHAR NewKeyW[] = {'N','e','w','K','e','y',0};
2876 static const WCHAR AValueW[] = {'A','V','a','l','u','e',0};
2878 if(!pSHSetIniStringW || is_win2k_and_lower){
2879 win_skip("SHSetIniStringW is not available\n");
2880 return;
2883 if (!write_inifile(TestIniW))
2884 return;
2886 ret = pSHSetIniStringW(TestAppW, AKeyW, AValueW, TestIniW);
2887 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2888 todo_wine /* wine sticks an extra \r\n at the end of the file */
2889 verify_inifile(TestIniW, "[TestApp]\r\nAKey=AValue\r\nAnotherKey=asdf\r\n");
2891 ret = pSHSetIniStringW(TestAppW, AKeyW, NULL, TestIniW);
2892 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2893 verify_inifile(TestIniW, "[TestApp]\r\nAnotherKey=asdf\r\n");
2895 ret = pSHSetIniStringW(AnotherAppW, NewKeyW, AValueW, TestIniW);
2896 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2897 verify_inifile(TestIniW, "[TestApp]\r\nAnotherKey=asdf\r\n[AnotherApp]\r\nNewKey=AValue\r\n");
2899 ret = pSHSetIniStringW(TestAppW, NULL, AValueW, TestIniW);
2900 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2901 verify_inifile(TestIniW, "[AnotherApp]\r\nNewKey=AValue\r\n");
2903 DeleteFileW(TestIniW);
2906 enum _shellkey_flags {
2907 SHKEY_Root_HKCU = 0x1,
2908 SHKEY_Root_HKLM = 0x2,
2909 SHKEY_Key_Explorer = 0x00,
2910 SHKEY_Key_Shell = 0x10,
2911 SHKEY_Key_ShellNoRoam = 0x20,
2912 SHKEY_Key_Classes = 0x30,
2913 SHKEY_Subkey_Default = 0x0000,
2914 SHKEY_Subkey_ResourceName = 0x1000,
2915 SHKEY_Subkey_Handlers = 0x2000,
2916 SHKEY_Subkey_Associations = 0x3000,
2917 SHKEY_Subkey_Volatile = 0x4000,
2918 SHKEY_Subkey_MUICache = 0x5000,
2919 SHKEY_Subkey_FileExts = 0x6000
2922 static void test_SHGetShellKey(void)
2924 static const WCHAR ShellFoldersW[] = { 'S','h','e','l','l',' ','F','o','l','d','e','r','s',0 };
2925 static const WCHAR WineTestW[] = { 'W','i','n','e','T','e','s','t',0 };
2927 void *pPathBuildRootW = GetProcAddress(hShlwapi, "PathBuildRootW");
2928 DWORD *alloc_data, data, size;
2929 HKEY hkey;
2930 HRESULT hres;
2932 if (!pSHGetShellKey)
2934 win_skip("SHGetShellKey(ordinal 491) isn't available\n");
2935 return;
2938 /* some win2k */
2939 if (pPathBuildRootW && pPathBuildRootW == pSHGetShellKey)
2941 win_skip("SHGetShellKey(ordinal 491) used for PathBuildRootW\n");
2942 return;
2945 if (is_win9x || is_win2k_and_lower)
2947 win_skip("Ordinal 491 used for another call, skipping SHGetShellKey tests\n");
2948 return;
2951 /* Vista+ limits SHKEY enumeration values */
2952 SetLastError(0xdeadbeef);
2953 hkey = pSHGetShellKey(SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2954 if (hkey)
2956 /* Tests not working on Vista+ */
2957 RegCloseKey(hkey);
2959 hkey = pSHGetShellKey(SHKEY_Root_HKLM|SHKEY_Key_Classes, NULL, FALSE);
2960 ok(hkey != NULL, "hkey = NULL\n");
2961 RegCloseKey(hkey);
2964 hkey = pSHGetShellKey(SHKEY_Root_HKCU|SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2965 ok(hkey != NULL, "hkey = NULL\n");
2966 RegCloseKey(hkey);
2968 hkey = pSHGetShellKey(SHKEY_Root_HKLM|SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2969 ok(hkey != NULL, "hkey = NULL\n");
2970 RegCloseKey(hkey);
2972 hkey = pSHGetShellKey(SHKEY_Root_HKLM, WineTestW, FALSE);
2973 ok(hkey == NULL, "hkey != NULL\n");
2975 hkey = pSHGetShellKey(SHKEY_Root_HKLM, NULL, FALSE);
2976 ok(hkey != NULL, "Can't open key\n");
2977 ok(SUCCEEDED(RegDeleteKeyW(hkey, WineTestW)), "Can't delete key\n");
2978 RegCloseKey(hkey);
2980 hkey = pSHGetShellKey(SHKEY_Root_HKLM, WineTestW, TRUE);
2981 if (!hkey && GetLastError() == ERROR_ACCESS_DENIED)
2983 skip("Not authorized to create keys\n");
2984 return;
2986 ok(hkey != NULL, "Can't create key\n");
2987 RegCloseKey(hkey);
2989 if (!pSKGetValueW || !pSKSetValueW || !pSKDeleteValueW || !pSKAllocValueW)
2991 win_skip("SKGetValueW, SKSetValueW, SKDeleteValueW or SKAllocValueW not available\n");
2992 return;
2995 size = sizeof(data);
2996 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
2997 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres);
2999 data = 1234;
3000 hres = pSKSetValueW(SHKEY_Root_HKLM, WineTestW, NULL, REG_DWORD, &data, sizeof(DWORD));
3001 ok(hres == S_OK, "hres = %x\n", hres);
3003 size = 1;
3004 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, NULL, &size);
3005 ok(hres == S_OK, "hres = %x\n", hres);
3006 ok(size == sizeof(DWORD), "size = %d\n", size);
3008 data = 0xdeadbeef;
3009 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
3010 ok(hres == S_OK, "hres = %x\n", hres);
3011 ok(size == sizeof(DWORD), "size = %d\n", size);
3012 ok(data == 1234, "data = %d\n", data);
3014 hres = pSKAllocValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, (void**)&alloc_data, &size);
3015 ok(hres == S_OK, "hres= %x\n", hres);
3016 ok(size == sizeof(DWORD), "size = %d\n", size);
3017 if (SUCCEEDED(hres))
3019 ok(*alloc_data == 1234, "*alloc_data = %d\n", *alloc_data);
3020 LocalFree(alloc_data);
3023 hres = pSKDeleteValueW(SHKEY_Root_HKLM, WineTestW, NULL);
3024 ok(hres == S_OK, "hres = %x\n", hres);
3026 hres = pSKDeleteValueW(SHKEY_Root_HKLM, WineTestW, NULL);
3027 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres);
3029 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
3030 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres);
3032 hkey = pSHGetShellKey(SHKEY_Root_HKLM, NULL, FALSE);
3033 ok(hkey != NULL, "Can't create key\n");
3034 ok(SUCCEEDED(RegDeleteKeyW(hkey, WineTestW)), "Can't delete key\n");
3035 RegCloseKey(hkey);
3038 static void init_pointers(void)
3040 #define MAKEFUNC(f, ord) (p##f = (void*)GetProcAddress(hShlwapi, (LPSTR)(ord)))
3041 MAKEFUNC(SHAllocShared, 7);
3042 MAKEFUNC(SHLockShared, 8);
3043 MAKEFUNC(SHUnlockShared, 9);
3044 MAKEFUNC(SHFreeShared, 10);
3045 MAKEFUNC(SHMapHandle, 11);
3046 MAKEFUNC(GetAcceptLanguagesA, 14);
3047 MAKEFUNC(SHSetWindowBits, 165);
3048 MAKEFUNC(SHSetParentHwnd, 167);
3049 MAKEFUNC(ConnectToConnectionPoint, 168);
3050 MAKEFUNC(SHSearchMapInt, 198);
3051 MAKEFUNC(SHCreateWorkerWindowA, 257);
3052 MAKEFUNC(GUIDFromStringA, 269);
3053 MAKEFUNC(SHPackDispParams, 282);
3054 MAKEFUNC(IConnectionPoint_InvokeWithCancel, 283);
3055 MAKEFUNC(IConnectionPoint_SimpleInvoke, 284);
3056 MAKEFUNC(SHGetIniStringW, 294);
3057 MAKEFUNC(SHSetIniStringW, 295);
3058 MAKEFUNC(SHFormatDateTimeA, 353);
3059 MAKEFUNC(SHFormatDateTimeW, 354);
3060 MAKEFUNC(SHIShellFolder_EnumObjects, 404);
3061 MAKEFUNC(SHGetObjectCompatFlags, 476);
3062 MAKEFUNC(IUnknown_QueryServiceExec, 484);
3063 MAKEFUNC(SHGetShellKey, 491);
3064 MAKEFUNC(SHPropertyBag_ReadLONG, 496);
3065 MAKEFUNC(IUnknown_ProfferService, 514);
3066 MAKEFUNC(SKGetValueW, 516);
3067 MAKEFUNC(SKSetValueW, 517);
3068 MAKEFUNC(SKDeleteValueW, 518);
3069 MAKEFUNC(SKAllocValueW, 519);
3070 #undef MAKEFUNC
3073 static void test_SHSetParentHwnd(void)
3075 HWND hwnd, hwnd2, ret;
3076 DWORD style;
3078 if (!pSHSetParentHwnd)
3080 win_skip("SHSetParentHwnd not available\n");
3081 return;
3084 hwnd = CreateWindowA("Button", "", WS_VISIBLE, 0, 0, 10, 10, NULL, NULL, NULL, NULL);
3085 ok(hwnd != NULL, "got %p\n", hwnd);
3087 hwnd2 = CreateWindowA("Button", "", WS_VISIBLE | WS_CHILD, 0, 0, 10, 10, hwnd, NULL, NULL, NULL);
3088 ok(hwnd2 != NULL, "got %p\n", hwnd2);
3090 /* null params */
3091 ret = pSHSetParentHwnd(NULL, NULL);
3092 ok(ret == NULL, "got %p\n", ret);
3094 /* set to no parent while already no parent present */
3095 ret = GetParent(hwnd);
3096 ok(ret == NULL, "got %p\n", ret);
3097 style = GetWindowLongA(hwnd, GWL_STYLE);
3098 ok((style & (WS_POPUP|WS_CHILD)) == 0, "got style 0x%08x\n", style);
3099 ret = pSHSetParentHwnd(hwnd, NULL);
3100 ok(ret == NULL, "got %p\n", ret);
3101 style = GetWindowLongA(hwnd, GWL_STYLE);
3102 ok((style & (WS_POPUP|WS_CHILD)) == 0, "got style 0x%08x\n", style);
3104 /* reset to null parent from not null */
3105 ret = GetParent(hwnd2);
3106 ok(ret == hwnd, "got %p\n", ret);
3107 style = GetWindowLongA(hwnd2, GWL_STYLE);
3108 ok((style & (WS_POPUP|WS_CHILD)) == WS_CHILD, "got style 0x%08x\n", style);
3109 ret = pSHSetParentHwnd(hwnd2, NULL);
3110 ok(ret == NULL, "got %p\n", ret);
3111 style = GetWindowLongA(hwnd2, GWL_STYLE);
3112 ok((style & (WS_POPUP|WS_CHILD)) == WS_POPUP, "got style 0x%08x\n", style);
3113 ret = GetParent(hwnd2);
3114 ok(ret == NULL, "got %p\n", ret);
3116 /* set parent back */
3117 style = GetWindowLongA(hwnd2, GWL_STYLE);
3118 SetWindowLongA(hwnd2, GWL_STYLE, style & ~(WS_CHILD|WS_POPUP));
3119 style = GetWindowLongA(hwnd2, GWL_STYLE);
3120 ok((style & (WS_CHILD|WS_POPUP)) == 0, "got 0x%08x\n", style);
3122 ret = pSHSetParentHwnd(hwnd2, hwnd);
3123 todo_wine ok(ret == NULL, "got %p\n", ret);
3125 style = GetWindowLongA(hwnd2, GWL_STYLE);
3126 ok((style & (WS_POPUP|WS_CHILD)) == WS_CHILD, "got style 0x%08x\n", style);
3127 ret = GetParent(hwnd2);
3128 ok(ret == hwnd, "got %p\n", ret);
3130 /* try to set same parent again */
3131 /* with WS_POPUP */
3132 style = GetWindowLongA(hwnd2, GWL_STYLE);
3133 SetWindowLongA(hwnd2, GWL_STYLE, style | WS_POPUP);
3134 ret = pSHSetParentHwnd(hwnd2, hwnd);
3135 todo_wine ok(ret == NULL, "got %p\n", ret);
3136 style = GetWindowLongA(hwnd2, GWL_STYLE);
3137 ok((style & (WS_CHILD|WS_POPUP)) == WS_CHILD, "got 0x%08x\n", style);
3138 ret = GetParent(hwnd2);
3139 ok(ret == hwnd, "got %p\n", ret);
3141 /* without WS_POPUP */
3142 style = GetWindowLongA(hwnd2, GWL_STYLE);
3143 SetWindowLongA(hwnd2, GWL_STYLE, style | ~WS_POPUP);
3144 ret = pSHSetParentHwnd(hwnd2, hwnd);
3145 todo_wine ok(ret == hwnd, "got %p\n", ret);
3146 style = GetWindowLongA(hwnd2, GWL_STYLE);
3147 ok((style & (WS_CHILD|WS_POPUP)) == WS_CHILD, "got 0x%08x\n", style);
3148 ret = GetParent(hwnd2);
3149 ok(ret == hwnd, "got %p\n", ret);
3151 DestroyWindow(hwnd);
3152 DestroyWindow(hwnd2);
3155 START_TEST(ordinal)
3157 char **argv;
3158 int argc;
3160 hShlwapi = GetModuleHandleA("shlwapi.dll");
3161 is_win2k_and_lower = GetProcAddress(hShlwapi, "StrChrNW") == 0;
3162 is_win9x = GetProcAddress(hShlwapi, (LPSTR)99) == 0; /* StrCpyNXA */
3164 /* SHCreateStreamOnFileEx was introduced in shlwapi v6.0 */
3165 if(!GetProcAddress(hShlwapi, "SHCreateStreamOnFileEx")){
3166 win_skip("Too old shlwapi version\n");
3167 return;
3170 init_pointers();
3172 argc = winetest_get_mainargs(&argv);
3173 if (argc >= 4)
3175 DWORD procid;
3176 HANDLE hmem;
3177 sscanf(argv[2], "%d", &procid);
3178 sscanf(argv[3], "%p", &hmem);
3179 test_alloc_shared_remote(procid, hmem);
3180 return;
3183 hmlang = LoadLibraryA("mlang.dll");
3184 pLcidToRfc1766A = (void *)GetProcAddress(hmlang, "LcidToRfc1766A");
3186 hshell32 = LoadLibraryA("shell32.dll");
3187 pSHGetDesktopFolder = (void *)GetProcAddress(hshell32, "SHGetDesktopFolder");
3189 test_GetAcceptLanguagesA();
3190 test_SHSearchMapInt();
3191 test_alloc_shared(argc, argv);
3192 test_fdsa();
3193 test_GetShellSecurityDescriptor();
3194 test_SHPackDispParams();
3195 test_IConnectionPoint();
3196 test_SHPropertyBag_ReadLONG();
3197 test_SHSetWindowBits();
3198 test_SHFormatDateTimeA();
3199 test_SHFormatDateTimeW();
3200 test_SHGetObjectCompatFlags();
3201 test_IUnknown_QueryServiceExec();
3202 test_IUnknown_ProfferService();
3203 test_SHCreateWorkerWindowA();
3204 test_SHIShellFolder_EnumObjects();
3205 test_SHGetIniString();
3206 test_SHSetIniString();
3207 test_SHGetShellKey();
3208 test_SHSetParentHwnd();
3210 FreeLibrary(hshell32);
3211 FreeLibrary(hmlang);