gdi32: Avoid redundant computation of the gradient bounding rectangle.
[wine/multimedia.git] / dlls / shlwapi / tests / ordinal.c
blob0cb051846ab365e484ff003e37e842bdbe2b7dec
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 HRESULT(WINAPIV *pSHPackDispParams)(DISPPARAMS*,VARIANTARG*,UINT,...);
50 static HRESULT(WINAPI *pIConnectionPoint_SimpleInvoke)(IConnectionPoint*,DISPID,DISPPARAMS*);
51 static HRESULT(WINAPI *pIConnectionPoint_InvokeWithCancel)(IConnectionPoint*,DISPID,DISPPARAMS*,DWORD,DWORD);
52 static HRESULT(WINAPI *pConnectToConnectionPoint)(IUnknown*,REFIID,BOOL,IUnknown*, LPDWORD,IConnectionPoint **);
53 static HRESULT(WINAPI *pSHPropertyBag_ReadLONG)(IPropertyBag *,LPCWSTR,LPLONG);
54 static LONG (WINAPI *pSHSetWindowBits)(HWND, INT, UINT, UINT);
55 static INT (WINAPI *pSHFormatDateTimeA)(const FILETIME UNALIGNED*, DWORD*, LPSTR, UINT);
56 static INT (WINAPI *pSHFormatDateTimeW)(const FILETIME UNALIGNED*, DWORD*, LPWSTR, UINT);
57 static DWORD (WINAPI *pSHGetObjectCompatFlags)(IUnknown*, const CLSID*);
58 static BOOL (WINAPI *pGUIDFromStringA)(LPSTR, CLSID *);
59 static HRESULT (WINAPI *pIUnknown_QueryServiceExec)(IUnknown*, REFIID, const GUID*, DWORD, DWORD, VARIANT*, VARIANT*);
60 static HRESULT (WINAPI *pIUnknown_ProfferService)(IUnknown*, REFGUID, IServiceProvider*, DWORD*);
61 static HWND (WINAPI *pSHCreateWorkerWindowA)(LONG, HWND, DWORD, DWORD, HMENU, LONG_PTR);
62 static HRESULT (WINAPI *pSHIShellFolder_EnumObjects)(LPSHELLFOLDER, HWND, SHCONTF, IEnumIDList**);
63 static DWORD (WINAPI *pSHGetIniStringW)(LPCWSTR, LPCWSTR, LPWSTR, DWORD, LPCWSTR);
64 static BOOL (WINAPI *pSHSetIniStringW)(LPCWSTR, LPCWSTR, LPCWSTR, LPCWSTR);
65 static HKEY (WINAPI *pSHGetShellKey)(DWORD, LPCWSTR, BOOL);
66 static HRESULT (WINAPI *pSKGetValueW)(DWORD, LPCWSTR, LPCWSTR, DWORD*, void*, DWORD*);
67 static HRESULT (WINAPI *pSKSetValueW)(DWORD, LPCWSTR, LPCWSTR, DWORD, void*, DWORD);
68 static HRESULT (WINAPI *pSKDeleteValueW)(DWORD, LPCWSTR, LPCWSTR);
69 static HRESULT (WINAPI *pSKAllocValueW)(DWORD, LPCWSTR, LPCWSTR, DWORD*, void**, DWORD*);
70 static HWND (WINAPI *pSHSetParentHwnd)(HWND, HWND);
72 static HMODULE hmlang;
73 static HRESULT (WINAPI *pLcidToRfc1766A)(LCID, LPSTR, INT);
75 static HMODULE hshell32;
76 static HRESULT (WINAPI *pSHGetDesktopFolder)(IShellFolder**);
78 static const CHAR ie_international[] = {
79 'S','o','f','t','w','a','r','e','\\',
80 'M','i','c','r','o','s','o','f','t','\\',
81 'I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r','\\',
82 'I','n','t','e','r','n','a','t','i','o','n','a','l',0};
83 static const CHAR acceptlanguage[] = {
84 'A','c','c','e','p','t','L','a','n','g','u','a','g','e',0};
86 static int strcmp_wa(LPCWSTR strw, const char *stra)
88 CHAR buf[512];
89 WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL);
90 return lstrcmpA(stra, buf);
93 typedef struct {
94 int id;
95 const void *args[5];
96 } call_entry_t;
98 typedef struct {
99 call_entry_t *calls;
100 int count;
101 int alloc;
102 } call_trace_t;
104 static void init_call_trace(call_trace_t *ctrace)
106 ctrace->alloc = 10;
107 ctrace->count = 0;
108 ctrace->calls = HeapAlloc(GetProcessHeap(), 0, sizeof(call_entry_t) * ctrace->alloc);
111 static void free_call_trace(const call_trace_t *ctrace)
113 HeapFree(GetProcessHeap(), 0, ctrace->calls);
116 static void add_call(call_trace_t *ctrace, int id, const void *arg0,
117 const void *arg1, const void *arg2, const void *arg3, const void *arg4)
119 call_entry_t call;
121 call.id = id;
122 call.args[0] = arg0;
123 call.args[1] = arg1;
124 call.args[2] = arg2;
125 call.args[3] = arg3;
126 call.args[4] = arg4;
128 if (ctrace->count == ctrace->alloc)
130 ctrace->alloc *= 2;
131 ctrace->calls = HeapReAlloc(GetProcessHeap(),0, ctrace->calls, ctrace->alloc*sizeof(call_entry_t));
134 ctrace->calls[ctrace->count++] = call;
137 static void ok_trace_(call_trace_t *texpected, call_trace_t *tgot, int line)
139 if (texpected->count == tgot->count)
141 INT i;
142 /* compare */
143 for (i = 0; i < texpected->count; i++)
145 call_entry_t *expected = &texpected->calls[i];
146 call_entry_t *got = &tgot->calls[i];
147 INT j;
149 ok_(__FILE__, line)(expected->id == got->id, "got different ids %d: %d, %d\n", i+1, expected->id, got->id);
151 for (j = 0; j < 5; j++)
153 ok_(__FILE__, line)(expected->args[j] == got->args[j], "got different args[%d] for %d: %p, %p\n", j, i+1,
154 expected->args[j], got->args[j]);
158 else
159 ok_(__FILE__, line)(0, "traces length mismatch\n");
162 #define ok_trace(a, b) ok_trace_(a, b, __LINE__)
164 /* trace of actually made calls */
165 static call_trace_t trace_got;
167 static void test_GetAcceptLanguagesA(void)
169 static LPCSTR table[] = {"de,en-gb;q=0.7,en;q=0.3",
170 "de,en;q=0.3,en-gb;q=0.7", /* sorting is ignored */
171 "winetest", /* content is ignored */
172 "de-de,de;q=0.5",
173 "de",
174 NULL};
176 DWORD exactsize;
177 char original[512];
178 char language[32];
179 char buffer[64];
180 HKEY hroot = NULL;
181 LONG res_query = ERROR_SUCCESS;
182 LONG lres;
183 HRESULT hr;
184 DWORD maxlen = sizeof(buffer) - 2;
185 DWORD len;
186 LCID lcid;
187 LPCSTR entry;
188 INT i = 0;
190 if (!pGetAcceptLanguagesA) {
191 win_skip("GetAcceptLanguagesA is not available\n");
192 return;
195 lcid = GetUserDefaultLCID();
197 /* Get the original Value */
198 lres = RegOpenKeyA(HKEY_CURRENT_USER, ie_international, &hroot);
199 if (lres) {
200 skip("RegOpenKey(%s) failed: %d\n", ie_international, lres);
201 return;
203 len = sizeof(original);
204 original[0] = 0;
205 res_query = RegQueryValueExA(hroot, acceptlanguage, 0, NULL, (PBYTE)original, &len);
207 RegDeleteValue(hroot, acceptlanguage);
209 /* Some windows versions use "lang-COUNTRY" as default */
210 memset(language, 0, sizeof(language));
211 len = GetLocaleInfoA(lcid, LOCALE_SISO639LANGNAME, language, sizeof(language));
213 if (len) {
214 lstrcat(language, "-");
215 memset(buffer, 0, sizeof(buffer));
216 len = GetLocaleInfoA(lcid, LOCALE_SISO3166CTRYNAME, buffer, sizeof(buffer) - len - 1);
217 lstrcat(language, buffer);
219 else
221 /* LOCALE_SNAME has additional parts in some languages. Try only as last chance */
222 memset(language, 0, sizeof(language));
223 len = GetLocaleInfoA(lcid, LOCALE_SNAME, language, sizeof(language));
226 /* get the default value */
227 len = maxlen;
228 memset(buffer, '#', maxlen);
229 buffer[maxlen] = 0;
230 hr = pGetAcceptLanguagesA( buffer, &len);
232 if (hr != S_OK) {
233 win_skip("GetAcceptLanguagesA failed with 0x%x\n", hr);
234 goto restore_original;
237 if (lstrcmpA(buffer, language)) {
238 /* some windows versions use "lang" or "lang-country" as default */
239 language[0] = 0;
240 if (pLcidToRfc1766A) {
241 hr = pLcidToRfc1766A(lcid, language, sizeof(language));
242 ok(hr == S_OK, "LcidToRfc1766A returned 0x%x and %s\n", hr, language);
246 ok(!lstrcmpA(buffer, language),
247 "have '%s' (searching for '%s')\n", language, buffer);
249 if (lstrcmpA(buffer, language)) {
250 win_skip("no more ideas, how to build the default language '%s'\n", buffer);
251 goto restore_original;
254 trace("detected default: %s\n", language);
255 while ((entry = table[i])) {
257 exactsize = lstrlenA(entry);
259 lres = RegSetValueExA(hroot, acceptlanguage, 0, REG_SZ, (const BYTE *) entry, exactsize + 1);
260 ok(!lres, "got %d for RegSetValueExA: %s\n", lres, entry);
262 /* len includes space for the terminating 0 before vista/w2k8 */
263 len = exactsize + 2;
264 memset(buffer, '#', maxlen);
265 buffer[maxlen] = 0;
266 hr = pGetAcceptLanguagesA( buffer, &len);
267 ok(((hr == E_INVALIDARG) && (len == 0)) ||
268 (SUCCEEDED(hr) &&
269 ((len == exactsize) || (len == exactsize+1)) &&
270 !lstrcmpA(buffer, entry)),
271 "+2_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
273 len = exactsize + 1;
274 memset(buffer, '#', maxlen);
275 buffer[maxlen] = 0;
276 hr = pGetAcceptLanguagesA( buffer, &len);
277 ok(((hr == E_INVALIDARG) && (len == 0)) ||
278 (SUCCEEDED(hr) &&
279 ((len == exactsize) || (len == exactsize+1)) &&
280 !lstrcmpA(buffer, entry)),
281 "+1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
283 len = exactsize;
284 memset(buffer, '#', maxlen);
285 buffer[maxlen] = 0;
286 hr = pGetAcceptLanguagesA( buffer, &len);
288 /* There is no space for the string in the registry.
289 When the buffer is large enough, the default language is returned
291 When the buffer is too small for that fallback, win7_32 and w2k8_64
292 and above fail with HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), but
293 recent os succeed and return a partial result while
294 older os succeed and overflow the buffer */
296 ok(((hr == E_INVALIDARG) && (len == 0)) ||
297 (((hr == S_OK) && !lstrcmpA(buffer, language) && (len == lstrlenA(language))) ||
298 ((hr == S_OK) && !memcmp(buffer, language, len)) ||
299 ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len)),
300 "==_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
302 if (exactsize > 1) {
303 len = exactsize - 1;
304 memset(buffer, '#', maxlen);
305 buffer[maxlen] = 0;
306 hr = pGetAcceptLanguagesA( buffer, &len);
307 ok(((hr == E_INVALIDARG) && (len == 0)) ||
308 (((hr == S_OK) && !lstrcmpA(buffer, language) && (len == lstrlenA(language))) ||
309 ((hr == S_OK) && !memcmp(buffer, language, len)) ||
310 ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len)),
311 "-1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
314 len = 1;
315 memset(buffer, '#', maxlen);
316 buffer[maxlen] = 0;
317 hr = pGetAcceptLanguagesA( buffer, &len);
318 ok(((hr == E_INVALIDARG) && (len == 0)) ||
319 (((hr == S_OK) && !lstrcmpA(buffer, language) && (len == lstrlenA(language))) ||
320 ((hr == S_OK) && !memcmp(buffer, language, len)) ||
321 ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len)),
322 "=1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
324 len = maxlen;
325 hr = pGetAcceptLanguagesA( NULL, &len);
327 /* w2k3 and below: E_FAIL and untouched len,
328 since w2k8: S_OK and needed size (excluding 0) */
329 ok( ((hr == S_OK) && (len == exactsize)) ||
330 ((hr == E_FAIL) && (len == maxlen)),
331 "NULL,max #%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
333 i++;
336 /* without a value in the registry, a default language is returned */
337 RegDeleteValue(hroot, acceptlanguage);
339 len = maxlen;
340 memset(buffer, '#', maxlen);
341 buffer[maxlen] = 0;
342 hr = pGetAcceptLanguagesA( buffer, &len);
343 ok( ((hr == S_OK) && (len == lstrlenA(language))),
344 "max: got 0x%x with %d and %s (expected S_OK with %d and '%s'\n",
345 hr, len, buffer, lstrlenA(language), language);
347 len = 2;
348 memset(buffer, '#', maxlen);
349 buffer[maxlen] = 0;
350 hr = pGetAcceptLanguagesA( buffer, &len);
351 ok( (((hr == S_OK) || (hr == E_INVALIDARG)) && !memcmp(buffer, language, len)) ||
352 ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len),
353 "=2: got 0x%x with %d and %s\n", hr, len, buffer);
355 len = 1;
356 memset(buffer, '#', maxlen);
357 buffer[maxlen] = 0;
358 hr = pGetAcceptLanguagesA( buffer, &len);
359 /* When the buffer is too small, win7_32 and w2k8_64 and above fail with
360 HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), other versions suceed
361 and return a partial 0 terminated result while other versions
362 fail with E_INVALIDARG and return a partial unterminated result */
363 ok( (((hr == S_OK) || (hr == E_INVALIDARG)) && !memcmp(buffer, language, len)) ||
364 ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len),
365 "=1: got 0x%x with %d and %s\n", hr, len, buffer);
367 len = 0;
368 memset(buffer, '#', maxlen);
369 buffer[maxlen] = 0;
370 hr = pGetAcceptLanguagesA( buffer, &len);
371 /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG */
372 ok((hr == E_FAIL) || (hr == E_INVALIDARG),
373 "got 0x%x (expected E_FAIL or E_INVALIDARG)\n", hr);
375 memset(buffer, '#', maxlen);
376 buffer[maxlen] = 0;
377 hr = pGetAcceptLanguagesA( buffer, NULL);
378 /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG */
379 ok((hr == E_FAIL) || (hr == E_INVALIDARG),
380 "got 0x%x (expected E_FAIL or E_INVALIDARG)\n", hr);
383 hr = pGetAcceptLanguagesA( NULL, 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);
388 restore_original:
389 if (!res_query) {
390 len = lstrlenA(original);
391 lres = RegSetValueExA(hroot, acceptlanguage, 0, REG_SZ, (const BYTE *) original, len ? len + 1: 0);
392 ok(!lres, "RegSetValueEx(%s) failed: %d\n", original, lres);
394 else
396 RegDeleteValue(hroot, acceptlanguage);
398 RegCloseKey(hroot);
401 static void test_SHSearchMapInt(void)
403 int keys[8], values[8];
404 int i = 0;
406 if (!pSHSearchMapInt)
407 return;
409 memset(keys, 0, sizeof(keys));
410 memset(values, 0, sizeof(values));
411 keys[0] = 99; values[0] = 101;
413 /* NULL key/value lists crash native, so skip testing them */
415 /* 1 element */
416 i = pSHSearchMapInt(keys, values, 1, keys[0]);
417 ok(i == values[0], "Len 1, expected %d, got %d\n", values[0], i);
419 /* Key doesn't exist */
420 i = pSHSearchMapInt(keys, values, 1, 100);
421 ok(i == -1, "Len 1 - bad key, expected -1, got %d\n", i);
423 /* Len = 0 => not found */
424 i = pSHSearchMapInt(keys, values, 0, keys[0]);
425 ok(i == -1, "Len 1 - passed len 0, expected -1, got %d\n", i);
427 /* 2 elements, len = 1 */
428 keys[1] = 98; values[1] = 102;
429 i = pSHSearchMapInt(keys, values, 1, keys[1]);
430 ok(i == -1, "Len 1 - array len 2, expected -1, got %d\n", i);
432 /* 2 elements, len = 2 */
433 i = pSHSearchMapInt(keys, values, 2, keys[1]);
434 ok(i == values[1], "Len 2, expected %d, got %d\n", values[1], i);
436 /* Searches forward */
437 keys[2] = 99; values[2] = 103;
438 i = pSHSearchMapInt(keys, values, 3, keys[0]);
439 ok(i == values[0], "Len 3, expected %d, got %d\n", values[0], i);
442 static void test_alloc_shared(void)
444 DWORD procid;
445 HANDLE hmem;
446 int val;
447 int* p;
448 BOOL ret;
450 procid=GetCurrentProcessId();
451 hmem=pSHAllocShared(NULL,10,procid);
452 ok(hmem!=NULL,"SHAllocShared(NULL...) failed: %u\n", GetLastError());
453 ret = pSHFreeShared(hmem, procid);
454 ok( ret, "SHFreeShared failed: %u\n", GetLastError());
456 val=0x12345678;
457 hmem=pSHAllocShared(&val,4,procid);
458 ok(hmem!=NULL,"SHAllocShared(NULL...) failed: %u\n", GetLastError());
460 p=pSHLockShared(hmem,procid);
461 ok(p!=NULL,"SHLockShared failed: %u\n", GetLastError());
462 if (p!=NULL)
463 ok(*p==val,"Wrong value in shared memory: %d instead of %d\n",*p,val);
464 ret = pSHUnlockShared(p);
465 ok( ret, "SHUnlockShared failed: %u\n", GetLastError());
467 ret = pSHFreeShared(hmem, procid);
468 ok( ret, "SHFreeShared failed: %u\n", GetLastError());
471 static void test_fdsa(void)
473 typedef struct
475 DWORD num_items; /* Number of elements inserted */
476 void *mem; /* Ptr to array */
477 DWORD blocks_alloced; /* Number of elements allocated */
478 BYTE inc; /* Number of elements to grow by when we need to expand */
479 BYTE block_size; /* Size in bytes of an element */
480 BYTE flags; /* Flags */
481 } FDSA_info;
483 BOOL (WINAPI *pFDSA_Initialize)(DWORD block_size, DWORD inc, FDSA_info *info, void *mem,
484 DWORD init_blocks);
485 BOOL (WINAPI *pFDSA_Destroy)(FDSA_info *info);
486 DWORD (WINAPI *pFDSA_InsertItem)(FDSA_info *info, DWORD where, const void *block);
487 BOOL (WINAPI *pFDSA_DeleteItem)(FDSA_info *info, DWORD where);
489 FDSA_info info;
490 int block_size = 10, init_blocks = 4, inc = 2;
491 DWORD ret;
492 char *mem;
494 pFDSA_Initialize = (void *)GetProcAddress(hShlwapi, (LPSTR)208);
495 pFDSA_Destroy = (void *)GetProcAddress(hShlwapi, (LPSTR)209);
496 pFDSA_InsertItem = (void *)GetProcAddress(hShlwapi, (LPSTR)210);
497 pFDSA_DeleteItem = (void *)GetProcAddress(hShlwapi, (LPSTR)211);
499 mem = HeapAlloc(GetProcessHeap(), 0, block_size * init_blocks);
500 memset(&info, 0, sizeof(info));
502 ok(pFDSA_Initialize(block_size, inc, &info, mem, init_blocks), "FDSA_Initialize rets FALSE\n");
503 ok(info.num_items == 0, "num_items = %d\n", info.num_items);
504 ok(info.mem == mem, "mem = %p\n", info.mem);
505 ok(info.blocks_alloced == init_blocks, "blocks_alloced = %d\n", info.blocks_alloced);
506 ok(info.inc == inc, "inc = %d\n", info.inc);
507 ok(info.block_size == block_size, "block_size = %d\n", info.block_size);
508 ok(info.flags == 0, "flags = %d\n", info.flags);
510 ret = pFDSA_InsertItem(&info, 1234, "1234567890");
511 ok(ret == 0, "ret = %d\n", ret);
512 ok(info.num_items == 1, "num_items = %d\n", info.num_items);
513 ok(info.mem == mem, "mem = %p\n", info.mem);
514 ok(info.blocks_alloced == init_blocks, "blocks_alloced = %d\n", info.blocks_alloced);
515 ok(info.inc == inc, "inc = %d\n", info.inc);
516 ok(info.block_size == block_size, "block_size = %d\n", info.block_size);
517 ok(info.flags == 0, "flags = %d\n", info.flags);
519 ret = pFDSA_InsertItem(&info, 1234, "abcdefghij");
520 ok(ret == 1, "ret = %d\n", ret);
522 ret = pFDSA_InsertItem(&info, 1, "klmnopqrst");
523 ok(ret == 1, "ret = %d\n", ret);
525 ret = pFDSA_InsertItem(&info, 0, "uvwxyzABCD");
526 ok(ret == 0, "ret = %d\n", ret);
527 ok(info.mem == mem, "mem = %p\n", info.mem);
528 ok(info.flags == 0, "flags = %d\n", info.flags);
530 /* This next InsertItem will cause shlwapi to allocate its own mem buffer */
531 ret = pFDSA_InsertItem(&info, 0, "EFGHIJKLMN");
532 ok(ret == 0, "ret = %d\n", ret);
533 ok(info.mem != mem, "mem = %p\n", info.mem);
534 ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %d\n", info.blocks_alloced);
535 ok(info.flags == 0x1, "flags = %d\n", info.flags);
537 ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCD1234567890klmnopqrstabcdefghij", 50), "mem %s\n", (char*)info.mem);
539 ok(pFDSA_DeleteItem(&info, 2), "rets FALSE\n");
540 ok(info.mem != mem, "mem = %p\n", info.mem);
541 ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %d\n", info.blocks_alloced);
542 ok(info.flags == 0x1, "flags = %d\n", info.flags);
544 ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCDklmnopqrstabcdefghij", 40), "mem %s\n", (char*)info.mem);
546 ok(pFDSA_DeleteItem(&info, 3), "rets FALSE\n");
547 ok(info.mem != mem, "mem = %p\n", info.mem);
548 ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %d\n", info.blocks_alloced);
549 ok(info.flags == 0x1, "flags = %d\n", info.flags);
551 ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCDklmnopqrst", 30), "mem %s\n", (char*)info.mem);
553 ok(!pFDSA_DeleteItem(&info, 4), "does not ret FALSE\n");
555 /* As shlwapi has allocated memory internally, Destroy will ret FALSE */
556 ok(!pFDSA_Destroy(&info), "FDSA_Destroy does not ret FALSE\n");
559 /* When Initialize is called with inc = 0, set it to 1 */
560 ok(pFDSA_Initialize(block_size, 0, &info, mem, init_blocks), "FDSA_Initialize rets FALSE\n");
561 ok(info.inc == 1, "inc = %d\n", info.inc);
563 /* This time, because shlwapi hasn't had to allocate memory
564 internally, Destroy rets non-zero */
565 ok(pFDSA_Destroy(&info), "FDSA_Destroy rets FALSE\n");
568 HeapFree(GetProcessHeap(), 0, mem);
572 typedef struct SHELL_USER_SID {
573 SID_IDENTIFIER_AUTHORITY sidAuthority;
574 DWORD dwUserGroupID;
575 DWORD dwUserID;
576 } SHELL_USER_SID, *PSHELL_USER_SID;
577 typedef struct SHELL_USER_PERMISSION {
578 SHELL_USER_SID susID;
579 DWORD dwAccessType;
580 BOOL fInherit;
581 DWORD dwAccessMask;
582 DWORD dwInheritMask;
583 DWORD dwInheritAccessMask;
584 } SHELL_USER_PERMISSION, *PSHELL_USER_PERMISSION;
585 static void test_GetShellSecurityDescriptor(void)
587 SHELL_USER_PERMISSION supCurrentUserFull = {
588 { {SECURITY_NULL_SID_AUTHORITY}, 0, 0 },
589 ACCESS_ALLOWED_ACE_TYPE, FALSE,
590 GENERIC_ALL, 0, 0 };
591 #define MY_INHERITANCE 0xBE /* invalid value to proof behavior */
592 SHELL_USER_PERMISSION supEveryoneDenied = {
593 { {SECURITY_WORLD_SID_AUTHORITY}, SECURITY_WORLD_RID, 0 },
594 ACCESS_DENIED_ACE_TYPE, TRUE,
595 GENERIC_WRITE, MY_INHERITANCE | 0xDEADBA00, GENERIC_READ };
596 PSHELL_USER_PERMISSION rgsup[2] = {
597 &supCurrentUserFull, &supEveryoneDenied,
599 SECURITY_DESCRIPTOR* psd;
600 SECURITY_DESCRIPTOR* (WINAPI*pGetShellSecurityDescriptor)(PSHELL_USER_PERMISSION*,int);
601 void *pChrCmpIW = GetProcAddress(hShlwapi, "ChrCmpIW");
603 pGetShellSecurityDescriptor=(void*)GetProcAddress(hShlwapi,(char*)475);
605 if(!pGetShellSecurityDescriptor)
607 win_skip("GetShellSecurityDescriptor not available\n");
608 return;
611 if(pChrCmpIW && pChrCmpIW == pGetShellSecurityDescriptor) /* win2k */
613 win_skip("Skipping for GetShellSecurityDescriptor, same ordinal used for ChrCmpIW\n");
614 return;
617 psd = pGetShellSecurityDescriptor(NULL, 2);
618 ok(psd==NULL ||
619 broken(psd==INVALID_HANDLE_VALUE), /* IE5 */
620 "GetShellSecurityDescriptor should fail\n");
621 psd = pGetShellSecurityDescriptor(rgsup, 0);
622 ok(psd==NULL, "GetShellSecurityDescriptor should fail, got %p\n", psd);
624 SetLastError(0xdeadbeef);
625 psd = pGetShellSecurityDescriptor(rgsup, 2);
626 if (psd == NULL && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
628 /* The previous calls to GetShellSecurityDescriptor don't set the last error */
629 win_skip("GetShellSecurityDescriptor is not implemented\n");
630 return;
632 if (psd == INVALID_HANDLE_VALUE)
634 win_skip("GetShellSecurityDescriptor is broken on IE5\n");
635 return;
637 ok(psd!=NULL, "GetShellSecurityDescriptor failed\n");
638 if (psd!=NULL)
640 BOOL bHasDacl = FALSE, bDefaulted, ret;
641 PACL pAcl;
642 DWORD dwRev;
643 SECURITY_DESCRIPTOR_CONTROL control;
645 ok(IsValidSecurityDescriptor(psd), "returned value is not valid SD\n");
647 ret = GetSecurityDescriptorControl(psd, &control, &dwRev);
648 ok(ret, "GetSecurityDescriptorControl failed with error %u\n", GetLastError());
649 ok(0 == (control & SE_SELF_RELATIVE), "SD should be absolute\n");
651 ret = GetSecurityDescriptorDacl(psd, &bHasDacl, &pAcl, &bDefaulted);
652 ok(ret, "GetSecurityDescriptorDacl failed with error %u\n", GetLastError());
654 ok(bHasDacl, "SD has no DACL\n");
655 if (bHasDacl)
657 ok(!bDefaulted, "DACL should not be defaulted\n");
659 ok(pAcl != NULL, "NULL DACL!\n");
660 if (pAcl != NULL)
662 ACL_SIZE_INFORMATION asiSize;
664 ok(IsValidAcl(pAcl), "DACL is not valid\n");
666 ret = GetAclInformation(pAcl, &asiSize, sizeof(asiSize), AclSizeInformation);
667 ok(ret, "GetAclInformation failed with error %u\n", GetLastError());
669 ok(asiSize.AceCount == 3, "Incorrect number of ACEs: %d entries\n", asiSize.AceCount);
670 if (asiSize.AceCount == 3)
672 ACCESS_ALLOWED_ACE *paaa; /* will use for DENIED too */
674 ret = GetAce(pAcl, 0, (LPVOID*)&paaa);
675 ok(ret, "GetAce failed with error %u\n", GetLastError());
676 ok(paaa->Header.AceType == ACCESS_ALLOWED_ACE_TYPE,
677 "Invalid ACE type %d\n", paaa->Header.AceType);
678 ok(paaa->Header.AceFlags == 0, "Invalid ACE flags %x\n", paaa->Header.AceFlags);
679 ok(paaa->Mask == GENERIC_ALL, "Invalid ACE mask %x\n", paaa->Mask);
681 ret = GetAce(pAcl, 1, (LPVOID*)&paaa);
682 ok(ret, "GetAce failed with error %u\n", GetLastError());
683 ok(paaa->Header.AceType == ACCESS_DENIED_ACE_TYPE,
684 "Invalid ACE type %d\n", paaa->Header.AceType);
685 /* first one of two ACEs generated from inheritable entry - without inheritance */
686 ok(paaa->Header.AceFlags == 0, "Invalid ACE flags %x\n", paaa->Header.AceFlags);
687 ok(paaa->Mask == GENERIC_WRITE, "Invalid ACE mask %x\n", paaa->Mask);
689 ret = GetAce(pAcl, 2, (LPVOID*)&paaa);
690 ok(ret, "GetAce failed with error %u\n", GetLastError());
691 ok(paaa->Header.AceType == ACCESS_DENIED_ACE_TYPE,
692 "Invalid ACE type %d\n", paaa->Header.AceType);
693 /* second ACE - with inheritance */
694 ok(paaa->Header.AceFlags == MY_INHERITANCE,
695 "Invalid ACE flags %x\n", paaa->Header.AceFlags);
696 ok(paaa->Mask == GENERIC_READ, "Invalid ACE mask %x\n", paaa->Mask);
701 LocalFree(psd);
705 static void test_SHPackDispParams(void)
707 DISPPARAMS params;
708 VARIANT vars[10];
709 HRESULT hres;
711 if(!pSHPackDispParams)
712 win_skip("SHPackSidpParams not available\n");
714 memset(&params, 0xc0, sizeof(params));
715 memset(vars, 0xc0, sizeof(vars));
716 hres = pSHPackDispParams(&params, vars, 1, VT_I4, 0xdeadbeef);
717 ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres);
718 ok(params.cArgs == 1, "params.cArgs = %d\n", params.cArgs);
719 ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
720 ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
721 ok(params.rgvarg == vars, "params.rgvarg = %p\n", params.rgvarg);
722 ok(V_VT(vars) == VT_I4, "V_VT(var) = %d\n", V_VT(vars));
723 ok(V_I4(vars) == 0xdeadbeef, "failed %x\n", V_I4(vars));
725 memset(&params, 0xc0, sizeof(params));
726 hres = pSHPackDispParams(&params, NULL, 0, 0);
727 ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres);
728 ok(params.cArgs == 0, "params.cArgs = %d\n", params.cArgs);
729 ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
730 ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
731 ok(params.rgvarg == NULL, "params.rgvarg = %p\n", params.rgvarg);
733 memset(vars, 0xc0, sizeof(vars));
734 memset(&params, 0xc0, sizeof(params));
735 hres = pSHPackDispParams(&params, vars, 4, VT_BSTR, (void*)0xdeadbeef, VT_EMPTY, 10,
736 VT_I4, 100, VT_DISPATCH, (void*)0xdeadbeef);
737 ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres);
738 ok(params.cArgs == 4, "params.cArgs = %d\n", params.cArgs);
739 ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
740 ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
741 ok(params.rgvarg == vars, "params.rgvarg = %p\n", params.rgvarg);
742 ok(V_VT(vars) == VT_DISPATCH, "V_VT(vars[0]) = %x\n", V_VT(vars));
743 ok(V_I4(vars) == 0xdeadbeef, "V_I4(vars[0]) = %x\n", V_I4(vars));
744 ok(V_VT(vars+1) == VT_I4, "V_VT(vars[1]) = %d\n", V_VT(vars+1));
745 ok(V_I4(vars+1) == 100, "V_I4(vars[1]) = %x\n", V_I4(vars+1));
746 ok(V_VT(vars+2) == VT_I4, "V_VT(vars[2]) = %d\n", V_VT(vars+2));
747 ok(V_I4(vars+2) == 10, "V_I4(vars[2]) = %x\n", V_I4(vars+2));
748 ok(V_VT(vars+3) == VT_BSTR, "V_VT(vars[3]) = %d\n", V_VT(vars+3));
749 ok(V_BSTR(vars+3) == (void*)0xdeadbeef, "V_BSTR(vars[3]) = %p\n", V_BSTR(vars+3));
752 typedef struct _disp
754 IDispatch IDispatch_iface;
755 LONG refCount;
756 } Disp;
758 static inline Disp *impl_from_IDispatch(IDispatch *iface)
760 return CONTAINING_RECORD(iface, Disp, IDispatch_iface);
763 typedef struct _contain
765 IConnectionPointContainer IConnectionPointContainer_iface;
766 LONG refCount;
768 UINT ptCount;
769 IConnectionPoint **pt;
770 } Contain;
772 static inline Contain *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
774 return CONTAINING_RECORD(iface, Contain, IConnectionPointContainer_iface);
777 typedef struct _cntptn
779 IConnectionPoint IConnectionPoint_iface;
780 LONG refCount;
782 Contain *container;
783 GUID id;
784 UINT sinkCount;
785 IUnknown **sink;
786 } ConPt;
788 static inline ConPt *impl_from_IConnectionPoint(IConnectionPoint *iface)
790 return CONTAINING_RECORD(iface, ConPt, IConnectionPoint_iface);
793 typedef struct _enum
795 IEnumConnections IEnumConnections_iface;
796 LONG refCount;
798 UINT idx;
799 ConPt *pt;
800 } EnumCon;
802 static inline EnumCon *impl_from_IEnumConnections(IEnumConnections *iface)
804 return CONTAINING_RECORD(iface, EnumCon, IEnumConnections_iface);
807 typedef struct _enumpt
809 IEnumConnectionPoints IEnumConnectionPoints_iface;
810 LONG refCount;
812 int idx;
813 Contain *container;
814 } EnumPt;
816 static inline EnumPt *impl_from_IEnumConnectionPoints(IEnumConnectionPoints *iface)
818 return CONTAINING_RECORD(iface, EnumPt, IEnumConnectionPoints_iface);
822 static HRESULT WINAPI Disp_QueryInterface(
823 IDispatch* This,
824 REFIID riid,
825 void **ppvObject)
827 *ppvObject = NULL;
829 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDispatch))
831 *ppvObject = This;
834 if (*ppvObject)
836 IUnknown_AddRef(This);
837 return S_OK;
840 trace("no interface\n");
841 return E_NOINTERFACE;
844 static ULONG WINAPI Disp_AddRef(IDispatch* This)
846 Disp *iface = impl_from_IDispatch(This);
847 return InterlockedIncrement(&iface->refCount);
850 static ULONG WINAPI Disp_Release(IDispatch* This)
852 Disp *iface = impl_from_IDispatch(This);
853 ULONG ret;
855 ret = InterlockedDecrement(&iface->refCount);
856 if (ret == 0)
857 HeapFree(GetProcessHeap(),0,This);
858 return ret;
861 static HRESULT WINAPI Disp_GetTypeInfoCount(
862 IDispatch* This,
863 UINT *pctinfo)
865 return ERROR_SUCCESS;
868 static HRESULT WINAPI Disp_GetTypeInfo(
869 IDispatch* This,
870 UINT iTInfo,
871 LCID lcid,
872 ITypeInfo **ppTInfo)
874 return ERROR_SUCCESS;
877 static HRESULT WINAPI Disp_GetIDsOfNames(
878 IDispatch* This,
879 REFIID riid,
880 LPOLESTR *rgszNames,
881 UINT cNames,
882 LCID lcid,
883 DISPID *rgDispId)
885 return ERROR_SUCCESS;
888 static HRESULT WINAPI Disp_Invoke(
889 IDispatch* This,
890 DISPID dispIdMember,
891 REFIID riid,
892 LCID lcid,
893 WORD wFlags,
894 DISPPARAMS *pDispParams,
895 VARIANT *pVarResult,
896 EXCEPINFO *pExcepInfo,
897 UINT *puArgErr)
899 trace("%p %x %p %x %x %p %p %p %p\n",This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
901 ok(dispIdMember == 0xa0 || dispIdMember == 0xa1, "Unknown dispIdMember\n");
902 ok(pDispParams != NULL, "Invoked with NULL pDispParams\n");
903 ok(wFlags == DISPATCH_METHOD, "Wrong flags %x\n",wFlags);
904 ok(lcid == 0,"Wrong lcid %x\n",lcid);
905 if (dispIdMember == 0xa0)
907 ok(pDispParams->cArgs == 0, "params.cArgs = %d\n", pDispParams->cArgs);
908 ok(pDispParams->cNamedArgs == 0, "params.cNamedArgs = %d\n", pDispParams->cArgs);
909 ok(pDispParams->rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", pDispParams->rgdispidNamedArgs);
910 ok(pDispParams->rgvarg == NULL, "params.rgvarg = %p\n", pDispParams->rgvarg);
912 else if (dispIdMember == 0xa1)
914 ok(pDispParams->cArgs == 2, "params.cArgs = %d\n", pDispParams->cArgs);
915 ok(pDispParams->cNamedArgs == 0, "params.cNamedArgs = %d\n", pDispParams->cArgs);
916 ok(pDispParams->rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", pDispParams->rgdispidNamedArgs);
917 ok(V_VT(pDispParams->rgvarg) == VT_BSTR, "V_VT(var) = %d\n", V_VT(pDispParams->rgvarg));
918 ok(V_I4(pDispParams->rgvarg) == 0xdeadcafe , "failed %p\n", V_BSTR(pDispParams->rgvarg));
919 ok(V_VT(pDispParams->rgvarg+1) == VT_I4, "V_VT(var) = %d\n", V_VT(pDispParams->rgvarg+1));
920 ok(V_I4(pDispParams->rgvarg+1) == 0xdeadbeef, "failed %x\n", V_I4(pDispParams->rgvarg+1));
923 return ERROR_SUCCESS;
926 static const IDispatchVtbl disp_vtbl = {
927 Disp_QueryInterface,
928 Disp_AddRef,
929 Disp_Release,
931 Disp_GetTypeInfoCount,
932 Disp_GetTypeInfo,
933 Disp_GetIDsOfNames,
934 Disp_Invoke
937 static HRESULT WINAPI Enum_QueryInterface(
938 IEnumConnections* This,
939 REFIID riid,
940 void **ppvObject)
942 *ppvObject = NULL;
944 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumConnections))
946 *ppvObject = This;
949 if (*ppvObject)
951 IUnknown_AddRef(This);
952 return S_OK;
955 trace("no interface\n");
956 return E_NOINTERFACE;
959 static ULONG WINAPI Enum_AddRef(IEnumConnections* This)
961 EnumCon *iface = impl_from_IEnumConnections(This);
962 return InterlockedIncrement(&iface->refCount);
965 static ULONG WINAPI Enum_Release(IEnumConnections* This)
967 EnumCon *iface = impl_from_IEnumConnections(This);
968 ULONG ret;
970 ret = InterlockedDecrement(&iface->refCount);
971 if (ret == 0)
972 HeapFree(GetProcessHeap(),0,This);
973 return ret;
976 static HRESULT WINAPI Enum_Next(
977 IEnumConnections* This,
978 ULONG cConnections,
979 LPCONNECTDATA rgcd,
980 ULONG *pcFetched)
982 EnumCon *iface = impl_from_IEnumConnections(This);
984 if (cConnections > 0 && iface->idx < iface->pt->sinkCount)
986 rgcd->pUnk = iface->pt->sink[iface->idx];
987 IUnknown_AddRef(iface->pt->sink[iface->idx]);
988 rgcd->dwCookie=0xff;
989 if (pcFetched)
990 *pcFetched = 1;
991 iface->idx++;
992 return S_OK;
995 return E_FAIL;
998 static HRESULT WINAPI Enum_Skip(
999 IEnumConnections* This,
1000 ULONG cConnections)
1002 return E_FAIL;
1005 static HRESULT WINAPI Enum_Reset(
1006 IEnumConnections* This)
1008 return E_FAIL;
1011 static HRESULT WINAPI Enum_Clone(
1012 IEnumConnections* This,
1013 IEnumConnections **ppEnum)
1015 return E_FAIL;
1018 static const IEnumConnectionsVtbl enum_vtbl = {
1020 Enum_QueryInterface,
1021 Enum_AddRef,
1022 Enum_Release,
1023 Enum_Next,
1024 Enum_Skip,
1025 Enum_Reset,
1026 Enum_Clone
1029 static HRESULT WINAPI ConPt_QueryInterface(
1030 IConnectionPoint* This,
1031 REFIID riid,
1032 void **ppvObject)
1034 *ppvObject = NULL;
1036 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IConnectionPoint))
1038 *ppvObject = This;
1041 if (*ppvObject)
1043 IUnknown_AddRef(This);
1044 return S_OK;
1047 trace("no interface\n");
1048 return E_NOINTERFACE;
1051 static ULONG WINAPI ConPt_AddRef(
1052 IConnectionPoint* This)
1054 ConPt *iface = impl_from_IConnectionPoint(This);
1055 return InterlockedIncrement(&iface->refCount);
1058 static ULONG WINAPI ConPt_Release(
1059 IConnectionPoint* This)
1061 ConPt *iface = impl_from_IConnectionPoint(This);
1062 ULONG ret;
1064 ret = InterlockedDecrement(&iface->refCount);
1065 if (ret == 0)
1067 if (iface->sinkCount > 0)
1069 int i;
1070 for (i = 0; i < iface->sinkCount; i++)
1072 if (iface->sink[i])
1073 IUnknown_Release(iface->sink[i]);
1075 HeapFree(GetProcessHeap(),0,iface->sink);
1077 HeapFree(GetProcessHeap(),0,This);
1079 return ret;
1082 static HRESULT WINAPI ConPt_GetConnectionInterface(
1083 IConnectionPoint* This,
1084 IID *pIID)
1086 static int i = 0;
1087 ConPt *iface = impl_from_IConnectionPoint(This);
1088 if (i==0)
1090 i++;
1091 return E_FAIL;
1093 else
1094 memcpy(pIID,&iface->id,sizeof(GUID));
1095 return S_OK;
1098 static HRESULT WINAPI ConPt_GetConnectionPointContainer(
1099 IConnectionPoint* This,
1100 IConnectionPointContainer **ppCPC)
1102 ConPt *iface = impl_from_IConnectionPoint(This);
1104 *ppCPC = &iface->container->IConnectionPointContainer_iface;
1105 return S_OK;
1108 static HRESULT WINAPI ConPt_Advise(
1109 IConnectionPoint* This,
1110 IUnknown *pUnkSink,
1111 DWORD *pdwCookie)
1113 ConPt *iface = impl_from_IConnectionPoint(This);
1115 if (iface->sinkCount == 0)
1116 iface->sink = HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown*));
1117 else
1118 iface->sink = HeapReAlloc(GetProcessHeap(),0,iface->sink,sizeof(IUnknown*)*(iface->sinkCount+1));
1119 iface->sink[iface->sinkCount] = pUnkSink;
1120 IUnknown_AddRef(pUnkSink);
1121 iface->sinkCount++;
1122 *pdwCookie = iface->sinkCount;
1123 return S_OK;
1126 static HRESULT WINAPI ConPt_Unadvise(
1127 IConnectionPoint* This,
1128 DWORD dwCookie)
1130 ConPt *iface = impl_from_IConnectionPoint(This);
1132 if (dwCookie > iface->sinkCount)
1133 return E_FAIL;
1134 else
1136 IUnknown_Release(iface->sink[dwCookie-1]);
1137 iface->sink[dwCookie-1] = NULL;
1139 return S_OK;
1142 static HRESULT WINAPI ConPt_EnumConnections(
1143 IConnectionPoint* This,
1144 IEnumConnections **ppEnum)
1146 EnumCon *ec;
1148 ec = HeapAlloc(GetProcessHeap(),0,sizeof(EnumCon));
1149 ec->IEnumConnections_iface.lpVtbl = &enum_vtbl;
1150 ec->refCount = 1;
1151 ec->pt = impl_from_IConnectionPoint(This);
1152 ec->idx = 0;
1153 *ppEnum = &ec->IEnumConnections_iface;
1155 return S_OK;
1158 static const IConnectionPointVtbl point_vtbl = {
1159 ConPt_QueryInterface,
1160 ConPt_AddRef,
1161 ConPt_Release,
1163 ConPt_GetConnectionInterface,
1164 ConPt_GetConnectionPointContainer,
1165 ConPt_Advise,
1166 ConPt_Unadvise,
1167 ConPt_EnumConnections
1170 static HRESULT WINAPI EnumPt_QueryInterface(
1171 IEnumConnectionPoints* This,
1172 REFIID riid,
1173 void **ppvObject)
1175 *ppvObject = NULL;
1177 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumConnectionPoints))
1179 *ppvObject = This;
1182 if (*ppvObject)
1184 IUnknown_AddRef(This);
1185 return S_OK;
1188 trace("no interface\n");
1189 return E_NOINTERFACE;
1192 static ULONG WINAPI EnumPt_AddRef(IEnumConnectionPoints* This)
1194 EnumPt *iface = impl_from_IEnumConnectionPoints(This);
1195 return InterlockedIncrement(&iface->refCount);
1198 static ULONG WINAPI EnumPt_Release(IEnumConnectionPoints* This)
1200 EnumPt *iface = impl_from_IEnumConnectionPoints(This);
1201 ULONG ret;
1203 ret = InterlockedDecrement(&iface->refCount);
1204 if (ret == 0)
1205 HeapFree(GetProcessHeap(),0,This);
1206 return ret;
1209 static HRESULT WINAPI EnumPt_Next(
1210 IEnumConnectionPoints* This,
1211 ULONG cConnections,
1212 IConnectionPoint **rgcd,
1213 ULONG *pcFetched)
1215 EnumPt *iface = impl_from_IEnumConnectionPoints(This);
1217 if (cConnections > 0 && iface->idx < iface->container->ptCount)
1219 *rgcd = iface->container->pt[iface->idx];
1220 IUnknown_AddRef(iface->container->pt[iface->idx]);
1221 if (pcFetched)
1222 *pcFetched = 1;
1223 iface->idx++;
1224 return S_OK;
1227 return E_FAIL;
1230 static HRESULT WINAPI EnumPt_Skip(
1231 IEnumConnectionPoints* This,
1232 ULONG cConnections)
1234 return E_FAIL;
1237 static HRESULT WINAPI EnumPt_Reset(
1238 IEnumConnectionPoints* This)
1240 return E_FAIL;
1243 static HRESULT WINAPI EnumPt_Clone(
1244 IEnumConnectionPoints* This,
1245 IEnumConnectionPoints **ppEnumPt)
1247 return E_FAIL;
1250 static const IEnumConnectionPointsVtbl enumpt_vtbl = {
1252 EnumPt_QueryInterface,
1253 EnumPt_AddRef,
1254 EnumPt_Release,
1255 EnumPt_Next,
1256 EnumPt_Skip,
1257 EnumPt_Reset,
1258 EnumPt_Clone
1261 static HRESULT WINAPI Contain_QueryInterface(
1262 IConnectionPointContainer* This,
1263 REFIID riid,
1264 void **ppvObject)
1266 *ppvObject = NULL;
1268 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IConnectionPointContainer))
1270 *ppvObject = This;
1273 if (*ppvObject)
1275 IUnknown_AddRef(This);
1276 return S_OK;
1279 trace("no interface\n");
1280 return E_NOINTERFACE;
1283 static ULONG WINAPI Contain_AddRef(
1284 IConnectionPointContainer* This)
1286 Contain *iface = impl_from_IConnectionPointContainer(This);
1287 return InterlockedIncrement(&iface->refCount);
1290 static ULONG WINAPI Contain_Release(
1291 IConnectionPointContainer* This)
1293 Contain *iface = impl_from_IConnectionPointContainer(This);
1294 ULONG ret;
1296 ret = InterlockedDecrement(&iface->refCount);
1297 if (ret == 0)
1299 if (iface->ptCount > 0)
1301 int i;
1302 for (i = 0; i < iface->ptCount; i++)
1303 IUnknown_Release(iface->pt[i]);
1304 HeapFree(GetProcessHeap(),0,iface->pt);
1306 HeapFree(GetProcessHeap(),0,This);
1308 return ret;
1311 static HRESULT WINAPI Contain_EnumConnectionPoints(
1312 IConnectionPointContainer* This,
1313 IEnumConnectionPoints **ppEnum)
1315 EnumPt *ec;
1317 ec = HeapAlloc(GetProcessHeap(),0,sizeof(EnumPt));
1318 ec->IEnumConnectionPoints_iface.lpVtbl = &enumpt_vtbl;
1319 ec->refCount = 1;
1320 ec->idx= 0;
1321 ec->container = impl_from_IConnectionPointContainer(This);
1322 *ppEnum = &ec->IEnumConnectionPoints_iface;
1324 return S_OK;
1327 static HRESULT WINAPI Contain_FindConnectionPoint(
1328 IConnectionPointContainer* This,
1329 REFIID riid,
1330 IConnectionPoint **ppCP)
1332 Contain *iface = impl_from_IConnectionPointContainer(This);
1333 ConPt *pt;
1335 if (!IsEqualIID(riid, &IID_NULL) || iface->ptCount ==0)
1337 pt = HeapAlloc(GetProcessHeap(),0,sizeof(ConPt));
1338 pt->IConnectionPoint_iface.lpVtbl = &point_vtbl;
1339 pt->refCount = 1;
1340 pt->sinkCount = 0;
1341 pt->sink = NULL;
1342 pt->container = iface;
1343 pt->id = IID_IDispatch;
1345 if (iface->ptCount == 0)
1346 iface->pt =HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown*));
1347 else
1348 iface->pt = HeapReAlloc(GetProcessHeap(),0,iface->pt,sizeof(IUnknown*)*(iface->ptCount+1));
1349 iface->pt[iface->ptCount] = &pt->IConnectionPoint_iface;
1350 iface->ptCount++;
1352 *ppCP = &pt->IConnectionPoint_iface;
1354 else
1356 *ppCP = iface->pt[0];
1357 IUnknown_AddRef((IUnknown*)*ppCP);
1360 return S_OK;
1363 static const IConnectionPointContainerVtbl contain_vtbl = {
1364 Contain_QueryInterface,
1365 Contain_AddRef,
1366 Contain_Release,
1368 Contain_EnumConnectionPoints,
1369 Contain_FindConnectionPoint
1372 static void test_IConnectionPoint(void)
1374 HRESULT rc;
1375 ULONG ref;
1376 IConnectionPoint *point;
1377 Contain *container;
1378 Disp *dispatch;
1379 DWORD cookie = 0xffffffff;
1380 DISPPARAMS params;
1381 VARIANT vars[10];
1383 if (!pIConnectionPoint_SimpleInvoke || !pConnectToConnectionPoint)
1385 win_skip("IConnectionPoint Apis not present\n");
1386 return;
1389 container = HeapAlloc(GetProcessHeap(),0,sizeof(Contain));
1390 container->IConnectionPointContainer_iface.lpVtbl = &contain_vtbl;
1391 container->refCount = 1;
1392 container->ptCount = 0;
1393 container->pt = NULL;
1395 dispatch = HeapAlloc(GetProcessHeap(),0,sizeof(Disp));
1396 dispatch->IDispatch_iface.lpVtbl = &disp_vtbl;
1397 dispatch->refCount = 1;
1399 rc = pConnectToConnectionPoint((IUnknown*)dispatch, &IID_NULL, TRUE, (IUnknown*)container, &cookie, &point);
1400 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1401 ok(point != NULL, "returned ConnectionPoint is NULL\n");
1402 ok(cookie != 0xffffffff, "invalid cookie returned\n");
1404 rc = pIConnectionPoint_SimpleInvoke(point,0xa0,NULL);
1405 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1407 if (pSHPackDispParams)
1409 memset(&params, 0xc0, sizeof(params));
1410 memset(vars, 0xc0, sizeof(vars));
1411 rc = pSHPackDispParams(&params, vars, 2, VT_I4, 0xdeadbeef, VT_BSTR, 0xdeadcafe);
1412 ok(rc == S_OK, "SHPackDispParams failed: %08x\n", rc);
1414 rc = pIConnectionPoint_SimpleInvoke(point,0xa1,&params);
1415 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1417 else
1418 win_skip("pSHPackDispParams not present\n");
1420 rc = pConnectToConnectionPoint(NULL, &IID_NULL, FALSE, (IUnknown*)container, &cookie, NULL);
1421 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1423 /* MSDN says this should be required but it crashs on XP
1424 IUnknown_Release(point);
1426 ref = IUnknown_Release((IUnknown*)container);
1427 ok(ref == 0, "leftover IConnectionPointContainer reference %i\n",ref);
1428 ref = IUnknown_Release((IUnknown*)dispatch);
1429 ok(ref == 0, "leftover IDispatch reference %i\n",ref);
1432 typedef struct _propbag
1434 IPropertyBag IPropertyBag_iface;
1435 LONG refCount;
1437 } PropBag;
1439 static inline PropBag *impl_from_IPropertyBag(IPropertyBag *iface)
1441 return CONTAINING_RECORD(iface, PropBag, IPropertyBag_iface);
1445 static HRESULT WINAPI Prop_QueryInterface(
1446 IPropertyBag* This,
1447 REFIID riid,
1448 void **ppvObject)
1450 *ppvObject = NULL;
1452 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPropertyBag))
1454 *ppvObject = This;
1457 if (*ppvObject)
1459 IUnknown_AddRef(This);
1460 return S_OK;
1463 trace("no interface\n");
1464 return E_NOINTERFACE;
1467 static ULONG WINAPI Prop_AddRef(
1468 IPropertyBag* This)
1470 PropBag *iface = impl_from_IPropertyBag(This);
1471 return InterlockedIncrement(&iface->refCount);
1474 static ULONG WINAPI Prop_Release(
1475 IPropertyBag* This)
1477 PropBag *iface = impl_from_IPropertyBag(This);
1478 ULONG ret;
1480 ret = InterlockedDecrement(&iface->refCount);
1481 if (ret == 0)
1482 HeapFree(GetProcessHeap(),0,This);
1483 return ret;
1486 static HRESULT WINAPI Prop_Read(
1487 IPropertyBag* This,
1488 LPCOLESTR pszPropName,
1489 VARIANT *pVar,
1490 IErrorLog *pErrorLog)
1492 V_VT(pVar) = VT_BLOB|VT_BYREF;
1493 V_BYREF(pVar) = (LPVOID)0xdeadcafe;
1494 return S_OK;
1497 static HRESULT WINAPI Prop_Write(
1498 IPropertyBag* This,
1499 LPCOLESTR pszPropName,
1500 VARIANT *pVar)
1502 return S_OK;
1506 static const IPropertyBagVtbl prop_vtbl = {
1507 Prop_QueryInterface,
1508 Prop_AddRef,
1509 Prop_Release,
1511 Prop_Read,
1512 Prop_Write
1515 static void test_SHPropertyBag_ReadLONG(void)
1517 PropBag *pb;
1518 HRESULT rc;
1519 LONG out;
1520 static const WCHAR szName1[] = {'n','a','m','e','1',0};
1522 if (!pSHPropertyBag_ReadLONG)
1524 win_skip("SHPropertyBag_ReadLONG not present\n");
1525 return;
1528 pb = HeapAlloc(GetProcessHeap(),0,sizeof(PropBag));
1529 pb->refCount = 1;
1530 pb->IPropertyBag_iface.lpVtbl = &prop_vtbl;
1532 out = 0xfeedface;
1533 rc = pSHPropertyBag_ReadLONG(NULL, szName1, &out);
1534 ok(rc == E_INVALIDARG || broken(rc == 0), "incorrect return %x\n",rc);
1535 ok(out == 0xfeedface, "value should not have changed\n");
1536 rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, NULL, &out);
1537 ok(rc == E_INVALIDARG || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
1538 ok(out == 0xfeedface, "value should not have changed\n");
1539 rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, szName1, NULL);
1540 ok(rc == E_INVALIDARG || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
1541 ok(out == 0xfeedface, "value should not have changed\n");
1542 rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, szName1, &out);
1543 ok(rc == DISP_E_BADVARTYPE || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
1544 ok(out == 0xfeedface || broken(out == 0xfeedfa00), "value should not have changed %x\n",out);
1545 IUnknown_Release((IUnknown*)pb);
1550 static void test_SHSetWindowBits(void)
1552 HWND hwnd;
1553 DWORD style, styleold;
1554 WNDCLASSA clsA;
1556 if(!pSHSetWindowBits)
1558 win_skip("SHSetWindowBits is not available\n");
1559 return;
1562 clsA.style = 0;
1563 clsA.lpfnWndProc = DefWindowProcA;
1564 clsA.cbClsExtra = 0;
1565 clsA.cbWndExtra = 0;
1566 clsA.hInstance = GetModuleHandleA(NULL);
1567 clsA.hIcon = 0;
1568 clsA.hCursor = LoadCursorA(0, IDC_ARROW);
1569 clsA.hbrBackground = NULL;
1570 clsA.lpszMenuName = NULL;
1571 clsA.lpszClassName = "Shlwapi test class";
1572 RegisterClassA(&clsA);
1574 hwnd = CreateWindowA("Shlwapi test class", "Test", WS_VISIBLE, 0, 0, 100, 100,
1575 NULL, NULL, GetModuleHandle(NULL), 0);
1576 ok(IsWindow(hwnd), "failed to create window\n");
1578 /* null window */
1579 SetLastError(0xdeadbeef);
1580 style = pSHSetWindowBits(NULL, GWL_STYLE, 0, 0);
1581 ok(style == 0, "expected 0 retval, got %d\n", style);
1582 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
1583 broken(GetLastError() == 0xdeadbeef), /* Win9x/WinMe */
1584 "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
1586 /* zero mask, zero flags */
1587 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1588 style = pSHSetWindowBits(hwnd, GWL_STYLE, 0, 0);
1589 ok(styleold == style, "expected old style\n");
1590 ok(styleold == GetWindowLongA(hwnd, GWL_STYLE), "expected to keep old style\n");
1592 /* test mask */
1593 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1594 ok(styleold & WS_VISIBLE, "expected WS_VISIBLE\n");
1595 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1597 ok(style == styleold, "expected previous style, got %x\n", style);
1598 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1600 /* test mask, unset style bit used */
1601 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1602 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1603 ok(style == styleold, "expected previous style, got %x\n", style);
1604 ok(styleold == GetWindowLongA(hwnd, GWL_STYLE), "expected to keep old style\n");
1606 /* set back with flags */
1607 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1608 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, WS_VISIBLE);
1609 ok(style == styleold, "expected previous style, got %x\n", style);
1610 ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "expected updated style\n");
1612 /* reset and try to set without a mask */
1613 pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1614 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1615 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1616 style = pSHSetWindowBits(hwnd, GWL_STYLE, 0, WS_VISIBLE);
1617 ok(style == styleold, "expected previous style, got %x\n", style);
1618 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1620 DestroyWindow(hwnd);
1622 UnregisterClassA("Shlwapi test class", GetModuleHandleA(NULL));
1625 static void test_SHFormatDateTimeA(void)
1627 FILETIME UNALIGNED filetime;
1628 CHAR buff[100], buff2[100], buff3[100];
1629 SYSTEMTIME st;
1630 DWORD flags;
1631 INT ret;
1633 if(!pSHFormatDateTimeA)
1635 win_skip("pSHFormatDateTimeA isn't available\n");
1636 return;
1639 if (0)
1641 /* crashes on native */
1642 pSHFormatDateTimeA(NULL, NULL, NULL, 0);
1645 GetLocalTime(&st);
1646 SystemTimeToFileTime(&st, &filetime);
1647 /* SHFormatDateTime expects input as utc */
1648 LocalFileTimeToFileTime(&filetime, &filetime);
1650 /* no way to get required buffer length here */
1651 SetLastError(0xdeadbeef);
1652 ret = pSHFormatDateTimeA(&filetime, NULL, NULL, 0);
1653 ok(ret == 0, "got %d\n", ret);
1654 ok(GetLastError() == 0xdeadbeef || broken(GetLastError() == ERROR_SUCCESS /* Win7 */),
1655 "expected 0xdeadbeef, got %d\n", GetLastError());
1657 SetLastError(0xdeadbeef);
1658 buff[0] = 'a'; buff[1] = 0;
1659 ret = pSHFormatDateTimeA(&filetime, NULL, buff, 0);
1660 ok(ret == 0, "got %d\n", ret);
1661 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1662 ok(buff[0] == 'a', "expected same string, got %s\n", buff);
1664 /* flags needs to have FDTF_NOAUTOREADINGORDER for these tests to succeed on Vista+ */
1666 /* all combinations documented as invalid succeeded */
1667 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTTIME | FDTF_LONGTIME;
1668 SetLastError(0xdeadbeef);
1669 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1670 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1671 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1673 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_LONGDATE;
1674 SetLastError(0xdeadbeef);
1675 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1676 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1677 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1679 flags = FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE;
1680 SetLastError(0xdeadbeef);
1681 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1682 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1683 ok(GetLastError() == 0xdeadbeef ||
1684 broken(GetLastError() == ERROR_INVALID_FLAGS), /* Win9x/WinMe */
1685 "expected 0xdeadbeef, got %d\n", GetLastError());
1687 /* now check returned strings */
1688 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTTIME;
1689 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1690 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1691 ret = GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff2, sizeof(buff2));
1692 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1693 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1695 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGTIME;
1696 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1697 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1698 ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2));
1699 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1700 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1702 /* both time flags */
1703 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGTIME | FDTF_SHORTTIME;
1704 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1705 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1706 ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2));
1707 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1708 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1710 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE;
1711 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1712 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1713 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1714 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1715 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1717 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE;
1718 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1719 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1720 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1721 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1722 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1724 /* both date flags */
1725 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_SHORTDATE;
1726 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1727 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1728 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1729 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1730 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1732 /* various combinations of date/time flags */
1733 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_SHORTTIME;
1734 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1735 ok(ret == lstrlenA(buff)+1, "got %d, length %d\n", ret, lstrlenA(buff)+1);
1736 ret = GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3));
1737 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1738 ok(lstrcmpA(buff3, buff + lstrlenA(buff) - lstrlenA(buff3)) == 0,
1739 "expected (%s), got (%s) for time part\n",
1740 buff3, buff + lstrlenA(buff) - lstrlenA(buff3));
1741 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1742 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1743 buff[lstrlenA(buff2)] = '\0';
1744 ok(lstrcmpA(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1745 buff2, buff);
1747 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_LONGTIME;
1748 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1749 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1750 ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3));
1751 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1752 ok(lstrcmpA(buff3, buff + lstrlenA(buff) - lstrlenA(buff3)) == 0,
1753 "expected (%s), got (%s) for time part\n",
1754 buff3, buff + lstrlenA(buff) - lstrlenA(buff3));
1755 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1756 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1757 buff[lstrlenA(buff2)] = '\0';
1758 ok(lstrcmpA(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1759 buff2, buff);
1761 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_SHORTTIME;
1762 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1763 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1764 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1765 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1766 strcat(buff2, " ");
1767 ret = GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3));
1768 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1769 strcat(buff2, buff3);
1770 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1772 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_LONGTIME;
1773 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1774 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1775 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1776 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1777 strcat(buff2, " ");
1778 ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3));
1779 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1780 strcat(buff2, buff3);
1781 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1784 static void test_SHFormatDateTimeW(void)
1786 FILETIME UNALIGNED filetime;
1787 WCHAR buff[100], buff2[100], buff3[100], *p1, *p2;
1788 SYSTEMTIME st;
1789 DWORD flags;
1790 INT ret;
1791 static const WCHAR spaceW[] = {' ',0};
1792 #define UNICODE_LTR_MARK 0x200e
1794 if(!pSHFormatDateTimeW)
1796 win_skip("pSHFormatDateTimeW isn't available\n");
1797 return;
1800 if (0)
1802 /* crashes on native */
1803 pSHFormatDateTimeW(NULL, NULL, NULL, 0);
1806 GetLocalTime(&st);
1807 SystemTimeToFileTime(&st, &filetime);
1808 /* SHFormatDateTime expects input as utc */
1809 LocalFileTimeToFileTime(&filetime, &filetime);
1811 /* no way to get required buffer length here */
1812 SetLastError(0xdeadbeef);
1813 ret = pSHFormatDateTimeW(&filetime, NULL, NULL, 0);
1814 ok(ret == 0, "expected 0, got %d\n", ret);
1815 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1817 SetLastError(0xdeadbeef);
1818 buff[0] = 'a'; buff[1] = 0;
1819 ret = pSHFormatDateTimeW(&filetime, NULL, buff, 0);
1820 ok(ret == 0, "expected 0, got %d\n", ret);
1821 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1822 ok(buff[0] == 'a', "expected same string\n");
1824 /* all combinations documented as invalid succeeded */
1825 flags = FDTF_SHORTTIME | FDTF_LONGTIME;
1826 SetLastError(0xdeadbeef);
1827 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1828 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1829 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1830 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1832 flags = FDTF_SHORTDATE | FDTF_LONGDATE;
1833 SetLastError(0xdeadbeef);
1834 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1835 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1836 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1837 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1839 flags = FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE;
1840 SetLastError(0xdeadbeef);
1841 buff[0] = 0; /* NT4 doesn't clear the buffer on failure */
1842 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1843 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1844 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1845 ok(GetLastError() == 0xdeadbeef ||
1846 broken(GetLastError() == ERROR_INVALID_FLAGS), /* Win9x/WinMe/NT4 */
1847 "expected 0xdeadbeef, got %d\n", GetLastError());
1849 /* now check returned strings */
1850 flags = FDTF_SHORTTIME;
1851 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1852 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1853 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1854 SetLastError(0xdeadbeef);
1855 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1856 if (ret == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1858 win_skip("Needed W-functions are not implemented\n");
1859 return;
1861 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1862 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1864 flags = FDTF_LONGTIME;
1865 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1866 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1867 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1868 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1869 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1870 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1872 /* both time flags */
1873 flags = FDTF_LONGTIME | FDTF_SHORTTIME;
1874 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1875 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1876 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1877 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1878 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1879 ok(lstrcmpW(buff, buff2) == 0, "expected equal string\n");
1881 flags = FDTF_SHORTDATE;
1882 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1883 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1884 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1885 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1886 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1887 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1889 flags = FDTF_LONGDATE;
1890 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1891 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1892 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1893 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1894 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1895 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1897 /* both date flags */
1898 flags = FDTF_LONGDATE | FDTF_SHORTDATE;
1899 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1900 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1901 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1902 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1903 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1904 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1906 /* various combinations of date/time flags */
1907 flags = FDTF_LONGDATE | FDTF_SHORTTIME;
1908 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1909 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1910 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1911 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1912 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1913 ok(lstrcmpW(buff3, buff + lstrlenW(buff) - lstrlenW(buff3)) == 0,
1914 "expected (%s), got (%s) for time part\n",
1915 wine_dbgstr_w(buff3), wine_dbgstr_w(buff + lstrlenW(buff) - lstrlenW(buff3)));
1916 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1917 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1918 p1 = buff;
1919 p2 = buff2;
1920 while (*p2 != '\0')
1922 while (*p1 == UNICODE_LTR_MARK)
1923 p1++;
1924 while (*p2 == UNICODE_LTR_MARK)
1925 p2++;
1926 p1++;
1927 p2++;
1929 *p1 = '\0';
1930 ok(lstrcmpW(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1931 wine_dbgstr_w(buff2), wine_dbgstr_w(buff));
1933 flags = FDTF_LONGDATE | FDTF_LONGTIME;
1934 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1935 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1936 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1937 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1938 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1939 ok(lstrcmpW(buff3, buff + lstrlenW(buff) - lstrlenW(buff3)) == 0,
1940 "expected (%s), got (%s) for time part\n",
1941 wine_dbgstr_w(buff3), wine_dbgstr_w(buff + lstrlenW(buff) - lstrlenW(buff3)));
1942 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1943 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1944 p1 = buff;
1945 p2 = buff2;
1946 while (*p2 != '\0')
1948 while (*p1 == UNICODE_LTR_MARK)
1949 p1++;
1950 while (*p2 == UNICODE_LTR_MARK)
1951 p2++;
1952 p1++;
1953 p2++;
1955 *p1 = '\0';
1956 ok(lstrcmpW(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1957 wine_dbgstr_w(buff2), wine_dbgstr_w(buff));
1959 flags = FDTF_SHORTDATE | FDTF_SHORTTIME;
1960 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1961 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1962 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1963 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1964 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1965 lstrcatW(buff2, spaceW);
1966 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1967 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1968 lstrcatW(buff2, buff3);
1969 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1971 flags = FDTF_SHORTDATE | FDTF_LONGTIME;
1972 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1973 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1974 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1975 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1976 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1977 lstrcatW(buff2, spaceW);
1978 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1979 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1980 lstrcatW(buff2, buff3);
1981 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1984 static void test_SHGetObjectCompatFlags(void)
1986 struct compat_value {
1987 CHAR nameA[30];
1988 DWORD value;
1991 struct compat_value values[] = {
1992 { "OTNEEDSSFCACHE", 0x1 },
1993 { "NO_WEBVIEW", 0x2 },
1994 { "UNBINDABLE", 0x4 },
1995 { "PINDLL", 0x8 },
1996 { "NEEDSFILESYSANCESTOR", 0x10 },
1997 { "NOTAFILESYSTEM", 0x20 },
1998 { "CTXMENU_NOVERBS", 0x40 },
1999 { "CTXMENU_LIMITEDQI", 0x80 },
2000 { "COCREATESHELLFOLDERONLY", 0x100 },
2001 { "NEEDSSTORAGEANCESTOR", 0x200 },
2002 { "NOLEGACYWEBVIEW", 0x400 },
2003 { "CTXMENU_XPQCMFLAGS", 0x1000 },
2004 { "NOIPROPERTYSTORE", 0x2000 }
2007 static const char compat_path[] = "Software\\Microsoft\\Windows\\CurrentVersion\\ShellCompatibility\\Objects";
2008 void *pColorAdjustLuma = GetProcAddress(hShlwapi, "ColorAdjustLuma");
2009 CHAR keyA[39]; /* {CLSID} */
2010 HKEY root;
2011 DWORD ret;
2012 int i;
2014 if (!pSHGetObjectCompatFlags)
2016 win_skip("SHGetObjectCompatFlags isn't available\n");
2017 return;
2020 if (pColorAdjustLuma && pColorAdjustLuma == pSHGetObjectCompatFlags) /* win2k */
2022 win_skip("Skipping SHGetObjectCompatFlags, same ordinal used for ColorAdjustLuma\n");
2023 return;
2026 /* null args */
2027 ret = pSHGetObjectCompatFlags(NULL, NULL);
2028 ok(ret == 0, "got %d\n", ret);
2030 ret = RegOpenKeyA(HKEY_LOCAL_MACHINE, compat_path, &root);
2031 if (ret != ERROR_SUCCESS)
2033 skip("No compatibility class data found\n");
2034 return;
2037 for (i = 0; RegEnumKeyA(root, i, keyA, sizeof(keyA)) == ERROR_SUCCESS; i++)
2039 HKEY clsid_key;
2041 if (RegOpenKeyA(root, keyA, &clsid_key) == ERROR_SUCCESS)
2043 CHAR valueA[30];
2044 DWORD expected = 0, got, length = sizeof(valueA);
2045 CLSID clsid;
2046 int v;
2048 for (v = 0; RegEnumValueA(clsid_key, v, valueA, &length, NULL, NULL, NULL, NULL) == ERROR_SUCCESS; v++)
2050 int j;
2052 for (j = 0; j < sizeof(values)/sizeof(struct compat_value); j++)
2053 if (lstrcmpA(values[j].nameA, valueA) == 0)
2055 expected |= values[j].value;
2056 break;
2059 length = sizeof(valueA);
2062 pGUIDFromStringA(keyA, &clsid);
2063 got = pSHGetObjectCompatFlags(NULL, &clsid);
2064 ok(got == expected, "got 0x%08x, expected 0x%08x. Key %s\n", got, expected, keyA);
2066 RegCloseKey(clsid_key);
2070 RegCloseKey(root);
2073 typedef struct {
2074 IOleCommandTarget IOleCommandTarget_iface;
2075 LONG ref;
2076 } IOleCommandTargetImpl;
2078 static inline IOleCommandTargetImpl *impl_from_IOleCommandTarget(IOleCommandTarget *iface)
2080 return CONTAINING_RECORD(iface, IOleCommandTargetImpl, IOleCommandTarget_iface);
2083 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl;
2085 static IOleCommandTarget* IOleCommandTargetImpl_Construct(void)
2087 IOleCommandTargetImpl *obj;
2089 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2090 obj->IOleCommandTarget_iface.lpVtbl = &IOleCommandTargetImpl_Vtbl;
2091 obj->ref = 1;
2093 return &obj->IOleCommandTarget_iface;
2096 static HRESULT WINAPI IOleCommandTargetImpl_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppvObj)
2098 IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface);
2100 if (IsEqualIID(riid, &IID_IUnknown) ||
2101 IsEqualIID(riid, &IID_IOleCommandTarget))
2103 *ppvObj = This;
2106 if(*ppvObj)
2108 IUnknown_AddRef(iface);
2109 return S_OK;
2112 return E_NOINTERFACE;
2115 static ULONG WINAPI IOleCommandTargetImpl_AddRef(IOleCommandTarget *iface)
2117 IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface);
2118 return InterlockedIncrement(&This->ref);
2121 static ULONG WINAPI IOleCommandTargetImpl_Release(IOleCommandTarget *iface)
2123 IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface);
2124 ULONG ref = InterlockedDecrement(&This->ref);
2126 if (!ref)
2128 HeapFree(GetProcessHeap(), 0, This);
2129 return 0;
2131 return ref;
2134 static HRESULT WINAPI IOleCommandTargetImpl_QueryStatus(
2135 IOleCommandTarget *iface, const GUID *group, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText)
2137 return E_NOTIMPL;
2140 static HRESULT WINAPI IOleCommandTargetImpl_Exec(
2141 IOleCommandTarget *iface,
2142 const GUID *CmdGroup,
2143 DWORD nCmdID,
2144 DWORD nCmdexecopt,
2145 VARIANT *pvaIn,
2146 VARIANT *pvaOut)
2148 add_call(&trace_got, 3, CmdGroup, (void*)(DWORD_PTR)nCmdID, (void*)(DWORD_PTR)nCmdexecopt, pvaIn, pvaOut);
2149 return S_OK;
2152 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl =
2154 IOleCommandTargetImpl_QueryInterface,
2155 IOleCommandTargetImpl_AddRef,
2156 IOleCommandTargetImpl_Release,
2157 IOleCommandTargetImpl_QueryStatus,
2158 IOleCommandTargetImpl_Exec
2161 typedef struct {
2162 IServiceProvider IServiceProvider_iface;
2163 LONG ref;
2164 } IServiceProviderImpl;
2166 static inline IServiceProviderImpl *impl_from_IServiceProvider(IServiceProvider *iface)
2168 return CONTAINING_RECORD(iface, IServiceProviderImpl, IServiceProvider_iface);
2171 typedef struct {
2172 IProfferService IProfferService_iface;
2173 LONG ref;
2174 } IProfferServiceImpl;
2176 static inline IProfferServiceImpl *impl_from_IProfferService(IProfferService *iface)
2178 return CONTAINING_RECORD(iface, IProfferServiceImpl, IProfferService_iface);
2182 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl;
2183 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl;
2185 static IServiceProvider* IServiceProviderImpl_Construct(void)
2187 IServiceProviderImpl *obj;
2189 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2190 obj->IServiceProvider_iface.lpVtbl = &IServiceProviderImpl_Vtbl;
2191 obj->ref = 1;
2193 return &obj->IServiceProvider_iface;
2196 static IProfferService* IProfferServiceImpl_Construct(void)
2198 IProfferServiceImpl *obj;
2200 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2201 obj->IProfferService_iface.lpVtbl = &IProfferServiceImpl_Vtbl;
2202 obj->ref = 1;
2204 return &obj->IProfferService_iface;
2207 static HRESULT WINAPI IServiceProviderImpl_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppvObj)
2209 IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
2211 if (IsEqualIID(riid, &IID_IUnknown) ||
2212 IsEqualIID(riid, &IID_IServiceProvider))
2214 *ppvObj = This;
2217 if(*ppvObj)
2219 IUnknown_AddRef(iface);
2220 /* native uses redefined IID_IServiceProvider symbol, so we can't compare pointers */
2221 if (IsEqualIID(riid, &IID_IServiceProvider))
2222 add_call(&trace_got, 1, iface, &IID_IServiceProvider, 0, 0, 0);
2223 return S_OK;
2226 return E_NOINTERFACE;
2229 static ULONG WINAPI IServiceProviderImpl_AddRef(IServiceProvider *iface)
2231 IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
2232 return InterlockedIncrement(&This->ref);
2235 static ULONG WINAPI IServiceProviderImpl_Release(IServiceProvider *iface)
2237 IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
2238 ULONG ref = InterlockedDecrement(&This->ref);
2240 if (!ref)
2242 HeapFree(GetProcessHeap(), 0, This);
2243 return 0;
2245 return ref;
2248 static HRESULT WINAPI IServiceProviderImpl_QueryService(
2249 IServiceProvider *iface, REFGUID service, REFIID riid, void **ppv)
2251 /* native uses redefined pointer for IID_IOleCommandTarget, not one from uuid.lib */
2252 if (IsEqualIID(riid, &IID_IOleCommandTarget))
2254 add_call(&trace_got, 2, iface, service, &IID_IOleCommandTarget, 0, 0);
2255 *ppv = IOleCommandTargetImpl_Construct();
2257 if (IsEqualIID(riid, &IID_IProfferService))
2259 if (IsEqualIID(service, &IID_IProfferService))
2260 add_call(&trace_got, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2261 *ppv = IProfferServiceImpl_Construct();
2263 return S_OK;
2266 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl =
2268 IServiceProviderImpl_QueryInterface,
2269 IServiceProviderImpl_AddRef,
2270 IServiceProviderImpl_Release,
2271 IServiceProviderImpl_QueryService
2274 static void test_IUnknown_QueryServiceExec(void)
2276 IServiceProvider *provider = IServiceProviderImpl_Construct();
2277 static const GUID dummy_serviceid = { 0xdeadbeef };
2278 static const GUID dummy_groupid = { 0xbeefbeef };
2279 call_trace_t trace_expected;
2280 HRESULT hr;
2282 /* on <=W2K platforms same ordinal used for another export with different
2283 prototype, so skipping using this indirect condition */
2284 if (is_win2k_and_lower)
2286 win_skip("IUnknown_QueryServiceExec is not available\n");
2287 return;
2290 /* null source pointer */
2291 hr = pIUnknown_QueryServiceExec(NULL, &dummy_serviceid, &dummy_groupid, 0, 0, 0, 0);
2292 ok(hr == E_FAIL, "got 0x%08x\n", hr);
2294 /* expected trace:
2295 IUnknown_QueryServiceExec( ptr1, serviceid, groupid, arg1, arg2, arg3, arg4);
2296 -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &prov );
2297 -> IServiceProvider_QueryService( prov, serviceid, &IID_IOleCommandTarget, &obj );
2298 -> IOleCommandTarget_Exec( obj, groupid, arg1, arg2, arg3, arg4 );
2300 init_call_trace(&trace_expected);
2302 add_call(&trace_expected, 1, provider, &IID_IServiceProvider, 0, 0, 0);
2303 add_call(&trace_expected, 2, provider, &dummy_serviceid, &IID_IOleCommandTarget, 0, 0);
2304 add_call(&trace_expected, 3, &dummy_groupid, (void*)0x1, (void*)0x2, (void*)0x3, (void*)0x4);
2306 init_call_trace(&trace_got);
2307 hr = pIUnknown_QueryServiceExec((IUnknown*)provider, &dummy_serviceid, &dummy_groupid, 0x1, 0x2, (void*)0x3, (void*)0x4);
2308 ok(hr == S_OK, "got 0x%08x\n", hr);
2310 ok_trace(&trace_expected, &trace_got);
2312 free_call_trace(&trace_expected);
2313 free_call_trace(&trace_got);
2315 IServiceProvider_Release(provider);
2319 static HRESULT WINAPI IProfferServiceImpl_QueryInterface(IProfferService *iface, REFIID riid, void **ppvObj)
2321 IProfferServiceImpl *This = impl_from_IProfferService(iface);
2323 if (IsEqualIID(riid, &IID_IUnknown) ||
2324 IsEqualIID(riid, &IID_IProfferService))
2326 *ppvObj = This;
2328 else if (IsEqualIID(riid, &IID_IServiceProvider))
2330 *ppvObj = IServiceProviderImpl_Construct();
2331 add_call(&trace_got, 1, iface, &IID_IServiceProvider, 0, 0, 0);
2332 return S_OK;
2335 if(*ppvObj)
2337 IUnknown_AddRef(iface);
2338 return S_OK;
2341 return E_NOINTERFACE;
2344 static ULONG WINAPI IProfferServiceImpl_AddRef(IProfferService *iface)
2346 IProfferServiceImpl *This = impl_from_IProfferService(iface);
2347 return InterlockedIncrement(&This->ref);
2350 static ULONG WINAPI IProfferServiceImpl_Release(IProfferService *iface)
2352 IProfferServiceImpl *This = impl_from_IProfferService(iface);
2353 ULONG ref = InterlockedDecrement(&This->ref);
2355 if (!ref)
2357 HeapFree(GetProcessHeap(), 0, This);
2358 return 0;
2360 return ref;
2363 static HRESULT WINAPI IProfferServiceImpl_ProfferService(IProfferService *iface,
2364 REFGUID service, IServiceProvider *pService, DWORD *pCookie)
2366 *pCookie = 0xdeadbeef;
2367 add_call(&trace_got, 3, service, pService, pCookie, 0, 0);
2368 return S_OK;
2371 static HRESULT WINAPI IProfferServiceImpl_RevokeService(IProfferService *iface, DWORD cookie)
2373 add_call(&trace_got, 4, (void*)(DWORD_PTR)cookie, 0, 0, 0, 0);
2374 return S_OK;
2377 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl =
2379 IProfferServiceImpl_QueryInterface,
2380 IProfferServiceImpl_AddRef,
2381 IProfferServiceImpl_Release,
2382 IProfferServiceImpl_ProfferService,
2383 IProfferServiceImpl_RevokeService
2386 static void test_IUnknown_ProfferService(void)
2388 IServiceProvider *provider = IServiceProviderImpl_Construct();
2389 IProfferService *proff = IProfferServiceImpl_Construct();
2390 static const GUID dummy_serviceid = { 0xdeadbeef };
2391 call_trace_t trace_expected;
2392 HRESULT hr;
2393 DWORD cookie;
2395 /* on <=W2K platforms same ordinal used for another export with different
2396 prototype, so skipping using this indirect condition */
2397 if (is_win2k_and_lower)
2399 win_skip("IUnknown_ProfferService is not available\n");
2400 return;
2403 /* null source pointer */
2404 hr = pIUnknown_ProfferService(NULL, &dummy_serviceid, 0, 0);
2405 ok(hr == E_FAIL, "got 0x%08x\n", hr);
2407 /* expected trace:
2408 IUnknown_ProfferService( ptr1, serviceid, arg1, arg2);
2409 -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &provider );
2410 -> IServiceProvider_QueryService( provider, &IID_IProfferService, &IID_IProfferService, &proffer );
2412 if (service pointer not null):
2413 -> IProfferService_ProfferService( proffer, serviceid, arg1, arg2 );
2414 else
2415 -> IProfferService_RevokeService( proffer, *arg2 );
2417 init_call_trace(&trace_expected);
2419 add_call(&trace_expected, 1, proff, &IID_IServiceProvider, 0, 0, 0);
2420 add_call(&trace_expected, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2421 add_call(&trace_expected, 3, &dummy_serviceid, provider, &cookie, 0, 0);
2423 init_call_trace(&trace_got);
2424 cookie = 0;
2425 hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, provider, &cookie);
2426 ok(hr == S_OK, "got 0x%08x\n", hr);
2427 ok(cookie == 0xdeadbeef, "got %x\n", cookie);
2429 ok_trace(&trace_expected, &trace_got);
2430 free_call_trace(&trace_got);
2431 free_call_trace(&trace_expected);
2433 /* same with ::Revoke path */
2434 init_call_trace(&trace_expected);
2436 add_call(&trace_expected, 1, proff, &IID_IServiceProvider, 0, 0, 0);
2437 add_call(&trace_expected, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2438 add_call(&trace_expected, 4, (void*)(DWORD_PTR)cookie, 0, 0, 0, 0);
2440 init_call_trace(&trace_got);
2441 ok(cookie != 0, "got %x\n", cookie);
2442 hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, 0, &cookie);
2443 ok(hr == S_OK, "got 0x%08x\n", hr);
2444 ok(cookie == 0, "got %x\n", cookie);
2445 ok_trace(&trace_expected, &trace_got);
2446 free_call_trace(&trace_got);
2447 free_call_trace(&trace_expected);
2449 IServiceProvider_Release(provider);
2450 IProfferService_Release(proff);
2453 static void test_SHCreateWorkerWindowA(void)
2455 WNDCLASSA cliA;
2456 char classA[20];
2457 HWND hwnd;
2458 LONG_PTR ret;
2459 BOOL res;
2461 if (is_win2k_and_lower)
2463 win_skip("SHCreateWorkerWindowA not available\n");
2464 return;
2467 hwnd = pSHCreateWorkerWindowA(0, NULL, 0, 0, 0, 0);
2468 ok(hwnd != 0, "expected window\n");
2470 GetClassName(hwnd, classA, 20);
2471 ok(lstrcmpA(classA, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA);
2473 ret = GetWindowLongPtrA(hwnd, 0);
2474 ok(ret == 0, "got %ld\n", ret);
2476 /* class info */
2477 memset(&cliA, 0, sizeof(cliA));
2478 res = GetClassInfoA(GetModuleHandle("shlwapi.dll"), "WorkerA", &cliA);
2479 ok(res, "failed to get class info\n");
2480 ok(cliA.style == 0, "got 0x%08x\n", cliA.style);
2481 ok(cliA.cbClsExtra == 0, "got %d\n", cliA.cbClsExtra);
2482 ok(cliA.cbWndExtra == sizeof(LONG_PTR), "got %d\n", cliA.cbWndExtra);
2483 ok(cliA.lpszMenuName == 0, "got %s\n", cliA.lpszMenuName);
2485 DestroyWindow(hwnd);
2487 /* set extra bytes */
2488 hwnd = pSHCreateWorkerWindowA(0, NULL, 0, 0, 0, 0xdeadbeef);
2489 ok(hwnd != 0, "expected window\n");
2491 GetClassName(hwnd, classA, 20);
2492 ok(lstrcmpA(classA, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA);
2494 ret = GetWindowLongPtrA(hwnd, 0);
2495 ok(ret == 0xdeadbeef, "got %ld\n", ret);
2497 /* test exstyle */
2498 ret = GetWindowLongA(hwnd, GWL_EXSTYLE);
2499 ok(ret == WS_EX_WINDOWEDGE ||
2500 ret == (WS_EX_WINDOWEDGE|WS_EX_LAYOUTRTL) /* systems with RTL locale */, "0x%08lx\n", ret);
2502 DestroyWindow(hwnd);
2504 hwnd = pSHCreateWorkerWindowA(0, NULL, WS_EX_TOOLWINDOW, 0, 0, 0);
2505 ret = GetWindowLongA(hwnd, GWL_EXSTYLE);
2506 ok(ret == (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW) ||
2507 ret == (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW|WS_EX_LAYOUTRTL) /* systems with RTL locale */, "0x%08lx\n", ret);
2508 DestroyWindow(hwnd);
2511 static HRESULT WINAPI SF_QueryInterface(IShellFolder *iface,
2512 REFIID riid, void **ppv)
2514 /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */
2515 ok(!IsEqualGUID(&IID_IShellFolder, riid),
2516 "Unexpected QI for IShellFolder\n");
2517 return E_NOINTERFACE;
2520 static ULONG WINAPI SF_AddRef(IShellFolder *iface)
2522 return 2;
2525 static ULONG WINAPI SF_Release(IShellFolder *iface)
2527 return 1;
2530 static HRESULT WINAPI SF_ParseDisplayName(IShellFolder *iface,
2531 HWND owner, LPBC reserved, LPOLESTR displayName, ULONG *eaten,
2532 LPITEMIDLIST *idl, ULONG *attr)
2534 ok(0, "Didn't expect ParseDisplayName\n");
2535 return E_NOTIMPL;
2538 static HRESULT WINAPI SF_EnumObjects(IShellFolder *iface,
2539 HWND owner, SHCONTF flags, IEnumIDList **enm)
2541 *enm = (IEnumIDList*)0xcafebabe;
2542 return S_OK;
2545 static HRESULT WINAPI SF_BindToObject(IShellFolder *iface,
2546 LPCITEMIDLIST idl, LPBC reserved, REFIID riid, void **obj)
2548 ok(0, "Didn't expect BindToObject\n");
2549 return E_NOTIMPL;
2552 static HRESULT WINAPI SF_BindToStorage(IShellFolder *iface,
2553 LPCITEMIDLIST idl, LPBC reserved, REFIID riid, void **obj)
2555 ok(0, "Didn't expect BindToStorage\n");
2556 return E_NOTIMPL;
2559 static HRESULT WINAPI SF_CompareIDs(IShellFolder *iface,
2560 LPARAM lparam, LPCITEMIDLIST idl1, LPCITEMIDLIST idl2)
2562 ok(0, "Didn't expect CompareIDs\n");
2563 return E_NOTIMPL;
2566 static HRESULT WINAPI SF_CreateViewObject(IShellFolder *iface,
2567 HWND owner, REFIID riid, void **out)
2569 ok(0, "Didn't expect CreateViewObject\n");
2570 return E_NOTIMPL;
2573 static HRESULT WINAPI SF_GetAttributesOf(IShellFolder *iface,
2574 UINT cidl, LPCITEMIDLIST *idl, SFGAOF *inOut)
2576 ok(0, "Didn't expect GetAttributesOf\n");
2577 return E_NOTIMPL;
2580 static HRESULT WINAPI SF_GetUIObjectOf(IShellFolder *iface,
2581 HWND owner, UINT cidl, LPCITEMIDLIST *idls, REFIID riid, UINT *inOut,
2582 void **out)
2584 ok(0, "Didn't expect GetUIObjectOf\n");
2585 return E_NOTIMPL;
2588 static HRESULT WINAPI SF_GetDisplayNameOf(IShellFolder *iface,
2589 LPCITEMIDLIST idl, SHGDNF flags, STRRET *name)
2591 ok(0, "Didn't expect GetDisplayNameOf\n");
2592 return E_NOTIMPL;
2595 static HRESULT WINAPI SF_SetNameOf(IShellFolder *iface,
2596 HWND hwnd, LPCITEMIDLIST idl, LPCOLESTR name, SHGDNF flags,
2597 LPITEMIDLIST *idlOut)
2599 ok(0, "Didn't expect SetNameOf\n");
2600 return E_NOTIMPL;
2603 static IShellFolderVtbl ShellFolderVtbl = {
2604 SF_QueryInterface,
2605 SF_AddRef,
2606 SF_Release,
2607 SF_ParseDisplayName,
2608 SF_EnumObjects,
2609 SF_BindToObject,
2610 SF_BindToStorage,
2611 SF_CompareIDs,
2612 SF_CreateViewObject,
2613 SF_GetAttributesOf,
2614 SF_GetUIObjectOf,
2615 SF_GetDisplayNameOf,
2616 SF_SetNameOf
2619 static IShellFolder ShellFolder = { &ShellFolderVtbl };
2621 static void test_SHIShellFolder_EnumObjects(void)
2623 IEnumIDList *enm;
2624 HRESULT hres;
2625 IShellFolder *folder;
2627 if(!pSHIShellFolder_EnumObjects || is_win2k_and_lower){
2628 win_skip("SHIShellFolder_EnumObjects not available\n");
2629 return;
2632 if(0){
2633 /* NULL object crashes on Windows */
2634 pSHIShellFolder_EnumObjects(NULL, NULL, 0, NULL);
2637 /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */
2638 enm = (IEnumIDList*)0xdeadbeef;
2639 hres = pSHIShellFolder_EnumObjects(&ShellFolder, NULL, 0, &enm);
2640 ok(hres == S_OK, "SHIShellFolder_EnumObjects failed: 0x%08x\n", hres);
2641 ok(enm == (IEnumIDList*)0xcafebabe, "Didn't get expected enumerator location, instead: %p\n", enm);
2643 /* SHIShellFolder_EnumObjects isn't strict about the IShellFolder object */
2644 hres = pSHGetDesktopFolder(&folder);
2645 ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
2647 enm = NULL;
2648 hres = pSHIShellFolder_EnumObjects(folder, NULL, 0, &enm);
2649 ok(hres == S_OK, "SHIShellFolder_EnumObjects failed: 0x%08x\n", hres);
2650 ok(enm != NULL, "Didn't get an enumerator\n");
2651 if(enm)
2652 IEnumIDList_Release(enm);
2654 IShellFolder_Release(folder);
2657 static void write_inifile(LPCWSTR filename)
2659 DWORD written;
2660 HANDLE file;
2662 static const char data[] =
2663 "[TestApp]\r\n"
2664 "AKey=1\r\n"
2665 "AnotherKey=asdf\r\n";
2667 file = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
2668 if(file == INVALID_HANDLE_VALUE)
2669 return;
2671 WriteFile(file, data, sizeof(data), &written, NULL);
2673 CloseHandle(file);
2676 #define verify_inifile(f, e) r_verify_inifile(__LINE__, f, e)
2677 static void r_verify_inifile(unsigned l, LPCWSTR filename, LPCSTR exp)
2679 HANDLE file;
2680 CHAR buf[1024];
2681 DWORD read;
2683 file = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
2684 if(file == INVALID_HANDLE_VALUE)
2685 return;
2687 ReadFile(file, buf, sizeof(buf) * sizeof(CHAR), &read, NULL);
2688 buf[read] = '\0';
2690 CloseHandle(file);
2692 ok_(__FILE__,l)(!strcmp(buf, exp), "Expected:\n%s\nGot:\n%s\n", exp,
2693 buf);
2696 static void test_SHGetIniString(void)
2698 DWORD ret;
2699 WCHAR out[64] = {0};
2701 static const WCHAR TestAppW[] = {'T','e','s','t','A','p','p',0};
2702 static const WCHAR TestIniW[] = {'C',':','\\','t','e','s','t','.','i','n','i',0};
2703 static const WCHAR AKeyW[] = {'A','K','e','y',0};
2704 static const WCHAR AnotherKeyW[] = {'A','n','o','t','h','e','r','K','e','y',0};
2705 static const WCHAR JunkKeyW[] = {'J','u','n','k','K','e','y',0};
2707 if(!pSHGetIniStringW || is_win2k_and_lower){
2708 win_skip("SHGetIniStringW is not available\n");
2709 return;
2712 write_inifile(TestIniW);
2714 if(0){
2715 /* these crash on Windows */
2716 pSHGetIniStringW(NULL, NULL, NULL, 0, NULL);
2717 pSHGetIniStringW(NULL, AKeyW, out, sizeof(out), TestIniW);
2718 pSHGetIniStringW(TestAppW, AKeyW, NULL, sizeof(out), TestIniW);
2721 ret = pSHGetIniStringW(TestAppW, AKeyW, out, 0, TestIniW);
2722 ok(ret == 0, "SHGetIniStringW should have given 0, instead: %d\n", ret);
2724 /* valid arguments */
2725 ret = pSHGetIniStringW(TestAppW, NULL, out, sizeof(out), TestIniW);
2726 ok(broken(ret == 0) || /* win 98 */
2727 ret == 4, "SHGetIniStringW should have given 4, instead: %d\n", ret);
2728 ok(!lstrcmpW(out, AKeyW), "Expected %s, got: %s\n",
2729 wine_dbgstr_w(AKeyW), wine_dbgstr_w(out));
2731 ret = pSHGetIniStringW(TestAppW, AKeyW, out, sizeof(out), TestIniW);
2732 ok(broken(ret == 0) || /* win 98 */
2733 ret == 1, "SHGetIniStringW should have given 1, instead: %d\n", ret);
2734 ok(broken(*out == 0) || /*win 98 */
2735 !strcmp_wa(out, "1"), "Expected L\"1\", got: %s\n", wine_dbgstr_w(out));
2737 ret = pSHGetIniStringW(TestAppW, AnotherKeyW, out, sizeof(out), TestIniW);
2738 ok(broken(ret == 0) || /* win 98 */
2739 ret == 4, "SHGetIniStringW should have given 4, instead: %d\n", ret);
2740 ok(broken(*out == 0) || /* win 98 */
2741 !strcmp_wa(out, "asdf"), "Expected L\"asdf\", got: %s\n", wine_dbgstr_w(out));
2743 ret = pSHGetIniStringW(TestAppW, JunkKeyW, out, sizeof(out), TestIniW);
2744 ok(ret == 0, "SHGetIniStringW should have given 0, instead: %d\n", ret);
2745 ok(*out == 0, "Expected L\"\", got: %s\n", wine_dbgstr_w(out));
2747 DeleteFileW(TestIniW);
2750 static void test_SHSetIniString(void)
2752 BOOL ret;
2754 static const WCHAR TestAppW[] = {'T','e','s','t','A','p','p',0};
2755 static const WCHAR AnotherAppW[] = {'A','n','o','t','h','e','r','A','p','p',0};
2756 static const WCHAR TestIniW[] = {'C',':','\\','t','e','s','t','.','i','n','i',0};
2757 static const WCHAR AKeyW[] = {'A','K','e','y',0};
2758 static const WCHAR NewKeyW[] = {'N','e','w','K','e','y',0};
2759 static const WCHAR AValueW[] = {'A','V','a','l','u','e',0};
2761 if(!pSHSetIniStringW || is_win2k_and_lower){
2762 win_skip("SHSetIniStringW is not available\n");
2763 return;
2766 write_inifile(TestIniW);
2768 ret = pSHSetIniStringW(TestAppW, AKeyW, AValueW, TestIniW);
2769 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2770 todo_wine /* wine sticks an extra \r\n at the end of the file */
2771 verify_inifile(TestIniW, "[TestApp]\r\nAKey=AValue\r\nAnotherKey=asdf\r\n");
2773 ret = pSHSetIniStringW(TestAppW, AKeyW, NULL, TestIniW);
2774 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2775 verify_inifile(TestIniW, "[TestApp]\r\nAnotherKey=asdf\r\n");
2777 ret = pSHSetIniStringW(AnotherAppW, NewKeyW, AValueW, TestIniW);
2778 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2779 verify_inifile(TestIniW, "[TestApp]\r\nAnotherKey=asdf\r\n[AnotherApp]\r\nNewKey=AValue\r\n");
2781 ret = pSHSetIniStringW(TestAppW, NULL, AValueW, TestIniW);
2782 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2783 verify_inifile(TestIniW, "[AnotherApp]\r\nNewKey=AValue\r\n");
2785 DeleteFileW(TestIniW);
2788 enum _shellkey_flags {
2789 SHKEY_Root_HKCU = 0x1,
2790 SHKEY_Root_HKLM = 0x2,
2791 SHKEY_Key_Explorer = 0x00,
2792 SHKEY_Key_Shell = 0x10,
2793 SHKEY_Key_ShellNoRoam = 0x20,
2794 SHKEY_Key_Classes = 0x30,
2795 SHKEY_Subkey_Default = 0x0000,
2796 SHKEY_Subkey_ResourceName = 0x1000,
2797 SHKEY_Subkey_Handlers = 0x2000,
2798 SHKEY_Subkey_Associations = 0x3000,
2799 SHKEY_Subkey_Volatile = 0x4000,
2800 SHKEY_Subkey_MUICache = 0x5000,
2801 SHKEY_Subkey_FileExts = 0x6000
2804 static void test_SHGetShellKey(void)
2806 static const WCHAR ShellFoldersW[] = { 'S','h','e','l','l',' ','F','o','l','d','e','r','s',0 };
2807 static const WCHAR WineTestW[] = { 'W','i','n','e','T','e','s','t',0 };
2809 void *pPathBuildRootW = GetProcAddress(hShlwapi, "PathBuildRootW");
2810 DWORD *alloc_data, data, size;
2811 HKEY hkey;
2812 HRESULT hres;
2814 if (!pSHGetShellKey)
2816 win_skip("SHGetShellKey(ordinal 491) isn't available\n");
2817 return;
2820 /* some win2k */
2821 if (pPathBuildRootW && pPathBuildRootW == pSHGetShellKey)
2823 win_skip("SHGetShellKey(ordinal 491) used for PathBuildRootW\n");
2824 return;
2827 if (is_win9x || is_win2k_and_lower)
2829 win_skip("Ordinal 491 used for another call, skipping SHGetShellKey tests\n");
2830 return;
2833 /* Vista+ limits SHKEY enumeration values */
2834 SetLastError(0xdeadbeef);
2835 hkey = pSHGetShellKey(SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2836 if (hkey)
2838 /* Tests not working on Vista+ */
2839 RegCloseKey(hkey);
2841 hkey = pSHGetShellKey(SHKEY_Root_HKLM|SHKEY_Key_Classes, NULL, FALSE);
2842 ok(hkey != NULL, "hkey = NULL\n");
2843 RegCloseKey(hkey);
2846 hkey = pSHGetShellKey(SHKEY_Root_HKCU|SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2847 ok(hkey != NULL, "hkey = NULL\n");
2848 RegCloseKey(hkey);
2850 hkey = pSHGetShellKey(SHKEY_Root_HKLM|SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2851 ok(hkey != NULL, "hkey = NULL\n");
2852 RegCloseKey(hkey);
2854 hkey = pSHGetShellKey(SHKEY_Root_HKLM, WineTestW, FALSE);
2855 ok(hkey == NULL, "hkey != NULL\n");
2857 hkey = pSHGetShellKey(SHKEY_Root_HKLM, NULL, FALSE);
2858 ok(hkey != NULL, "Can't open key\n");
2859 ok(SUCCEEDED(RegDeleteKeyW(hkey, WineTestW)), "Can't delete key\n");
2860 RegCloseKey(hkey);
2862 hkey = pSHGetShellKey(SHKEY_Root_HKLM, WineTestW, TRUE);
2863 if (!hkey && GetLastError() == ERROR_ACCESS_DENIED)
2865 skip("Not authorized to create keys\n");
2866 return;
2868 ok(hkey != NULL, "Can't create key\n");
2869 RegCloseKey(hkey);
2871 if (!pSKGetValueW || !pSKSetValueW || !pSKDeleteValueW || !pSKAllocValueW)
2873 win_skip("SKGetValueW, SKSetValueW, SKDeleteValueW or SKAllocValueW not available\n");
2874 return;
2877 size = sizeof(data);
2878 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
2879 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres);
2881 data = 1234;
2882 hres = pSKSetValueW(SHKEY_Root_HKLM, WineTestW, NULL, REG_DWORD, &data, sizeof(DWORD));
2883 ok(hres == S_OK, "hres = %x\n", hres);
2885 size = 1;
2886 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, NULL, &size);
2887 ok(hres == S_OK, "hres = %x\n", hres);
2888 ok(size == sizeof(DWORD), "size = %d\n", size);
2890 data = 0xdeadbeef;
2891 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
2892 ok(hres == S_OK, "hres = %x\n", hres);
2893 ok(size == sizeof(DWORD), "size = %d\n", size);
2894 ok(data == 1234, "data = %d\n", data);
2896 hres = pSKAllocValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, (void**)&alloc_data, &size);
2897 ok(hres == S_OK, "hres= %x\n", hres);
2898 ok(size == sizeof(DWORD), "size = %d\n", size);
2899 if (SUCCEEDED(hres))
2901 ok(*alloc_data == 1234, "*alloc_data = %d\n", *alloc_data);
2902 LocalFree(alloc_data);
2905 hres = pSKDeleteValueW(SHKEY_Root_HKLM, WineTestW, NULL);
2906 ok(hres == S_OK, "hres = %x\n", hres);
2908 hres = pSKDeleteValueW(SHKEY_Root_HKLM, WineTestW, NULL);
2909 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres);
2911 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
2912 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres);
2914 hkey = pSHGetShellKey(SHKEY_Root_HKLM, NULL, FALSE);
2915 ok(hkey != NULL, "Can't create key\n");
2916 ok(SUCCEEDED(RegDeleteKeyW(hkey, WineTestW)), "Can't delete key\n");
2917 RegCloseKey(hkey);
2920 static void init_pointers(void)
2922 #define MAKEFUNC(f, ord) (p##f = (void*)GetProcAddress(hShlwapi, (LPSTR)(ord)))
2923 MAKEFUNC(SHAllocShared, 7);
2924 MAKEFUNC(SHLockShared, 8);
2925 MAKEFUNC(SHUnlockShared, 9);
2926 MAKEFUNC(SHFreeShared, 10);
2927 MAKEFUNC(GetAcceptLanguagesA, 14);
2928 MAKEFUNC(SHSetWindowBits, 165);
2929 MAKEFUNC(SHSetParentHwnd, 167);
2930 MAKEFUNC(ConnectToConnectionPoint, 168);
2931 MAKEFUNC(SHSearchMapInt, 198);
2932 MAKEFUNC(SHCreateWorkerWindowA, 257);
2933 MAKEFUNC(GUIDFromStringA, 269);
2934 MAKEFUNC(SHPackDispParams, 282);
2935 MAKEFUNC(IConnectionPoint_InvokeWithCancel, 283);
2936 MAKEFUNC(IConnectionPoint_SimpleInvoke, 284);
2937 MAKEFUNC(SHGetIniStringW, 294);
2938 MAKEFUNC(SHSetIniStringW, 295);
2939 MAKEFUNC(SHFormatDateTimeA, 353);
2940 MAKEFUNC(SHFormatDateTimeW, 354);
2941 MAKEFUNC(SHIShellFolder_EnumObjects, 404);
2942 MAKEFUNC(SHGetObjectCompatFlags, 476);
2943 MAKEFUNC(IUnknown_QueryServiceExec, 484);
2944 MAKEFUNC(SHGetShellKey, 491);
2945 MAKEFUNC(SHPropertyBag_ReadLONG, 496);
2946 MAKEFUNC(IUnknown_ProfferService, 514);
2947 MAKEFUNC(SKGetValueW, 516);
2948 MAKEFUNC(SKSetValueW, 517);
2949 MAKEFUNC(SKDeleteValueW, 518);
2950 MAKEFUNC(SKAllocValueW, 519);
2951 #undef MAKEFUNC
2954 static void test_SHSetParentHwnd(void)
2956 HWND hwnd, hwnd2, ret;
2957 DWORD style;
2959 if (!pSHSetParentHwnd)
2961 win_skip("SHSetParentHwnd not available\n");
2962 return;
2965 hwnd = CreateWindowA("Button", "", WS_VISIBLE, 0, 0, 10, 10, NULL, NULL, NULL, NULL);
2966 ok(hwnd != NULL, "got %p\n", hwnd);
2968 hwnd2 = CreateWindowA("Button", "", WS_VISIBLE | WS_CHILD, 0, 0, 10, 10, hwnd, NULL, NULL, NULL);
2969 ok(hwnd2 != NULL, "got %p\n", hwnd2);
2971 /* null params */
2972 ret = pSHSetParentHwnd(NULL, NULL);
2973 ok(ret == NULL, "got %p\n", ret);
2975 /* set to no parent while already no parent present */
2976 ret = GetParent(hwnd);
2977 ok(ret == NULL, "got %p\n", ret);
2978 style = GetWindowLongA(hwnd, GWL_STYLE);
2979 ok((style & (WS_POPUP|WS_CHILD)) == 0, "got style 0x%08x\n", style);
2980 ret = pSHSetParentHwnd(hwnd, NULL);
2981 ok(ret == NULL, "got %p\n", ret);
2982 style = GetWindowLongA(hwnd, GWL_STYLE);
2983 ok((style & (WS_POPUP|WS_CHILD)) == 0, "got style 0x%08x\n", style);
2985 /* reset to null parent from not null */
2986 ret = GetParent(hwnd2);
2987 ok(ret == hwnd, "got %p\n", ret);
2988 style = GetWindowLongA(hwnd2, GWL_STYLE);
2989 ok((style & (WS_POPUP|WS_CHILD)) == WS_CHILD, "got style 0x%08x\n", style);
2990 ret = pSHSetParentHwnd(hwnd2, NULL);
2991 ok(ret == NULL, "got %p\n", ret);
2992 style = GetWindowLongA(hwnd2, GWL_STYLE);
2993 ok((style & (WS_POPUP|WS_CHILD)) == WS_POPUP, "got style 0x%08x\n", style);
2994 ret = GetParent(hwnd2);
2995 ok(ret == NULL, "got %p\n", ret);
2997 /* set parent back */
2998 style = GetWindowLongA(hwnd2, GWL_STYLE);
2999 SetWindowLongA(hwnd2, GWL_STYLE, style & ~(WS_CHILD|WS_POPUP));
3000 style = GetWindowLongA(hwnd2, GWL_STYLE);
3001 ok((style & (WS_CHILD|WS_POPUP)) == 0, "got 0x%08x\n", style);
3003 ret = pSHSetParentHwnd(hwnd2, hwnd);
3004 todo_wine ok(ret == NULL, "got %p\n", ret);
3006 style = GetWindowLongA(hwnd2, GWL_STYLE);
3007 ok((style & (WS_POPUP|WS_CHILD)) == WS_CHILD, "got style 0x%08x\n", style);
3008 ret = GetParent(hwnd2);
3009 ok(ret == hwnd, "got %p\n", ret);
3011 /* try to set same parent again */
3012 /* with WS_POPUP */
3013 style = GetWindowLongA(hwnd2, GWL_STYLE);
3014 SetWindowLongA(hwnd2, GWL_STYLE, style | WS_POPUP);
3015 ret = pSHSetParentHwnd(hwnd2, hwnd);
3016 todo_wine ok(ret == NULL, "got %p\n", ret);
3017 style = GetWindowLongA(hwnd2, GWL_STYLE);
3018 ok((style & (WS_CHILD|WS_POPUP)) == WS_CHILD, "got 0x%08x\n", style);
3019 ret = GetParent(hwnd2);
3020 ok(ret == hwnd, "got %p\n", ret);
3022 /* without WS_POPUP */
3023 style = GetWindowLongA(hwnd2, GWL_STYLE);
3024 SetWindowLongA(hwnd2, GWL_STYLE, style | ~WS_POPUP);
3025 ret = pSHSetParentHwnd(hwnd2, hwnd);
3026 todo_wine ok(ret == hwnd, "got %p\n", ret);
3027 style = GetWindowLongA(hwnd2, GWL_STYLE);
3028 ok((style & (WS_CHILD|WS_POPUP)) == WS_CHILD, "got 0x%08x\n", style);
3029 ret = GetParent(hwnd2);
3030 ok(ret == hwnd, "got %p\n", ret);
3032 DestroyWindow(hwnd);
3033 DestroyWindow(hwnd2);
3036 START_TEST(ordinal)
3038 hShlwapi = GetModuleHandleA("shlwapi.dll");
3039 is_win2k_and_lower = GetProcAddress(hShlwapi, "StrChrNW") == 0;
3040 is_win9x = GetProcAddress(hShlwapi, (LPSTR)99) == 0; /* StrCpyNXA */
3042 /* SHCreateStreamOnFileEx was introduced in shlwapi v6.0 */
3043 if(!GetProcAddress(hShlwapi, "SHCreateStreamOnFileEx")){
3044 win_skip("Too old shlwapi version\n");
3045 return;
3048 init_pointers();
3050 hmlang = LoadLibraryA("mlang.dll");
3051 pLcidToRfc1766A = (void *)GetProcAddress(hmlang, "LcidToRfc1766A");
3053 hshell32 = LoadLibraryA("shell32.dll");
3054 pSHGetDesktopFolder = (void *)GetProcAddress(hshell32, "SHGetDesktopFolder");
3056 test_GetAcceptLanguagesA();
3057 test_SHSearchMapInt();
3058 test_alloc_shared();
3059 test_fdsa();
3060 test_GetShellSecurityDescriptor();
3061 test_SHPackDispParams();
3062 test_IConnectionPoint();
3063 test_SHPropertyBag_ReadLONG();
3064 test_SHSetWindowBits();
3065 test_SHFormatDateTimeA();
3066 test_SHFormatDateTimeW();
3067 test_SHGetObjectCompatFlags();
3068 test_IUnknown_QueryServiceExec();
3069 test_IUnknown_ProfferService();
3070 test_SHCreateWorkerWindowA();
3071 test_SHIShellFolder_EnumObjects();
3072 test_SHGetIniString();
3073 test_SHSetIniString();
3074 test_SHGetShellKey();
3075 test_SHSetParentHwnd();
3077 FreeLibrary(hshell32);
3078 FreeLibrary(hmlang);