shlwapi/tests: Skip some tests if not allowed to modify the registry.
[wine.git] / dlls / shlwapi / tests / ordinal.c
blob8316112ff88a541bcbee0b7ff295d8cb95ed217f
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*);
71 static HMODULE hmlang;
72 static HRESULT (WINAPI *pLcidToRfc1766A)(LCID, LPSTR, INT);
74 static HMODULE hshell32;
75 static HRESULT (WINAPI *pSHGetDesktopFolder)(IShellFolder**);
77 static const CHAR ie_international[] = {
78 'S','o','f','t','w','a','r','e','\\',
79 'M','i','c','r','o','s','o','f','t','\\',
80 'I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r','\\',
81 'I','n','t','e','r','n','a','t','i','o','n','a','l',0};
82 static const CHAR acceptlanguage[] = {
83 'A','c','c','e','p','t','L','a','n','g','u','a','g','e',0};
85 static int strcmp_wa(LPCWSTR strw, const char *stra)
87 CHAR buf[512];
88 WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL);
89 return lstrcmpA(stra, buf);
92 typedef struct {
93 int id;
94 const void *args[5];
95 } call_entry_t;
97 typedef struct {
98 call_entry_t *calls;
99 int count;
100 int alloc;
101 } call_trace_t;
103 static void init_call_trace(call_trace_t *ctrace)
105 ctrace->alloc = 10;
106 ctrace->count = 0;
107 ctrace->calls = HeapAlloc(GetProcessHeap(), 0, sizeof(call_entry_t) * ctrace->alloc);
110 static void free_call_trace(const call_trace_t *ctrace)
112 HeapFree(GetProcessHeap(), 0, ctrace->calls);
115 static void add_call(call_trace_t *ctrace, int id, const void *arg0,
116 const void *arg1, const void *arg2, const void *arg3, const void *arg4)
118 call_entry_t call;
120 call.id = id;
121 call.args[0] = arg0;
122 call.args[1] = arg1;
123 call.args[2] = arg2;
124 call.args[3] = arg3;
125 call.args[4] = arg4;
127 if (ctrace->count == ctrace->alloc)
129 ctrace->alloc *= 2;
130 ctrace->calls = HeapReAlloc(GetProcessHeap(),0, ctrace->calls, ctrace->alloc*sizeof(call_entry_t));
133 ctrace->calls[ctrace->count++] = call;
136 static void ok_trace_(call_trace_t *texpected, call_trace_t *tgot, int line)
138 if (texpected->count == tgot->count)
140 INT i;
141 /* compare */
142 for (i = 0; i < texpected->count; i++)
144 call_entry_t *expected = &texpected->calls[i];
145 call_entry_t *got = &tgot->calls[i];
146 INT j;
148 ok_(__FILE__, line)(expected->id == got->id, "got different ids %d: %d, %d\n", i+1, expected->id, got->id);
150 for (j = 0; j < 5; j++)
152 ok_(__FILE__, line)(expected->args[j] == got->args[j], "got different args[%d] for %d: %p, %p\n", j, i+1,
153 expected->args[j], got->args[j]);
157 else
158 ok_(__FILE__, line)(0, "traces length mismatch\n");
161 #define ok_trace(a, b) ok_trace_(a, b, __LINE__)
163 /* trace of actually made calls */
164 static call_trace_t trace_got;
166 static void test_GetAcceptLanguagesA(void)
168 static LPCSTR table[] = {"de,en-gb;q=0.7,en;q=0.3",
169 "de,en;q=0.3,en-gb;q=0.7", /* sorting is ignored */
170 "winetest", /* content is ignored */
171 "de-de,de;q=0.5",
172 "de",
173 NULL};
175 DWORD exactsize;
176 char original[512];
177 char language[32];
178 char buffer[64];
179 HKEY hroot = NULL;
180 LONG res_query = ERROR_SUCCESS;
181 LONG lres;
182 HRESULT hr;
183 DWORD maxlen = sizeof(buffer) - 2;
184 DWORD len;
185 LCID lcid;
186 LPCSTR entry;
187 INT i = 0;
189 if (!pGetAcceptLanguagesA) {
190 win_skip("GetAcceptLanguagesA is not available\n");
191 return;
194 lcid = GetUserDefaultLCID();
196 /* Get the original Value */
197 lres = RegOpenKeyA(HKEY_CURRENT_USER, ie_international, &hroot);
198 if (lres) {
199 skip("RegOpenKey(%s) failed: %d\n", ie_international, lres);
200 return;
202 len = sizeof(original);
203 original[0] = 0;
204 res_query = RegQueryValueExA(hroot, acceptlanguage, 0, NULL, (PBYTE)original, &len);
206 RegDeleteValue(hroot, acceptlanguage);
208 /* Some windows versions use "lang-COUNTRY" as default */
209 memset(language, 0, sizeof(language));
210 len = GetLocaleInfoA(lcid, LOCALE_SISO639LANGNAME, language, sizeof(language));
212 if (len) {
213 lstrcat(language, "-");
214 memset(buffer, 0, sizeof(buffer));
215 len = GetLocaleInfoA(lcid, LOCALE_SISO3166CTRYNAME, buffer, sizeof(buffer) - len - 1);
216 lstrcat(language, buffer);
218 else
220 /* LOCALE_SNAME has additional parts in some languages. Try only as last chance */
221 memset(language, 0, sizeof(language));
222 len = GetLocaleInfoA(lcid, LOCALE_SNAME, language, sizeof(language));
225 /* get the default value */
226 len = maxlen;
227 memset(buffer, '#', maxlen);
228 buffer[maxlen] = 0;
229 hr = pGetAcceptLanguagesA( buffer, &len);
231 if (hr != S_OK) {
232 win_skip("GetAcceptLanguagesA failed with 0x%x\n", hr);
233 goto restore_original;
236 if (lstrcmpA(buffer, language)) {
237 /* some windows versions use "lang" or "lang-country" as default */
238 language[0] = 0;
239 if (pLcidToRfc1766A) {
240 hr = pLcidToRfc1766A(lcid, language, sizeof(language));
241 ok(hr == S_OK, "LcidToRfc1766A returned 0x%x and %s\n", hr, language);
245 ok(!lstrcmpA(buffer, language),
246 "have '%s' (searching for '%s')\n", language, buffer);
248 if (lstrcmpA(buffer, language)) {
249 win_skip("no more ideas, how to build the default language '%s'\n", buffer);
250 goto restore_original;
253 trace("detected default: %s\n", language);
254 while ((entry = table[i])) {
256 exactsize = lstrlenA(entry);
258 lres = RegSetValueExA(hroot, acceptlanguage, 0, REG_SZ, (const BYTE *) entry, exactsize + 1);
259 ok(!lres, "got %d for RegSetValueExA: %s\n", lres, entry);
261 /* len includes space for the terminating 0 before vista/w2k8 */
262 len = exactsize + 2;
263 memset(buffer, '#', maxlen);
264 buffer[maxlen] = 0;
265 hr = pGetAcceptLanguagesA( buffer, &len);
266 ok(((hr == E_INVALIDARG) && (len == 0)) ||
267 (SUCCEEDED(hr) &&
268 ((len == exactsize) || (len == exactsize+1)) &&
269 !lstrcmpA(buffer, entry)),
270 "+2_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
272 len = exactsize + 1;
273 memset(buffer, '#', maxlen);
274 buffer[maxlen] = 0;
275 hr = pGetAcceptLanguagesA( buffer, &len);
276 ok(((hr == E_INVALIDARG) && (len == 0)) ||
277 (SUCCEEDED(hr) &&
278 ((len == exactsize) || (len == exactsize+1)) &&
279 !lstrcmpA(buffer, entry)),
280 "+1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
282 len = exactsize;
283 memset(buffer, '#', maxlen);
284 buffer[maxlen] = 0;
285 hr = pGetAcceptLanguagesA( buffer, &len);
287 /* There is no space for the string in the registry.
288 When the buffer is large enough, the default language is returned
290 When the buffer is too small for that fallback, win7_32 and w2k8_64
291 and above fail with HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), but
292 recent os succeed and return a partial result while
293 older os succeed and overflow the buffer */
295 ok(((hr == E_INVALIDARG) && (len == 0)) ||
296 (((hr == S_OK) && !lstrcmpA(buffer, language) && (len == lstrlenA(language))) ||
297 ((hr == S_OK) && !memcmp(buffer, language, len)) ||
298 ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len)),
299 "==_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
301 if (exactsize > 1) {
302 len = exactsize - 1;
303 memset(buffer, '#', maxlen);
304 buffer[maxlen] = 0;
305 hr = pGetAcceptLanguagesA( buffer, &len);
306 ok(((hr == E_INVALIDARG) && (len == 0)) ||
307 (((hr == S_OK) && !lstrcmpA(buffer, language) && (len == lstrlenA(language))) ||
308 ((hr == S_OK) && !memcmp(buffer, language, len)) ||
309 ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len)),
310 "-1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
313 len = 1;
314 memset(buffer, '#', maxlen);
315 buffer[maxlen] = 0;
316 hr = pGetAcceptLanguagesA( buffer, &len);
317 ok(((hr == E_INVALIDARG) && (len == 0)) ||
318 (((hr == S_OK) && !lstrcmpA(buffer, language) && (len == lstrlenA(language))) ||
319 ((hr == S_OK) && !memcmp(buffer, language, len)) ||
320 ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len)),
321 "=1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
323 len = maxlen;
324 hr = pGetAcceptLanguagesA( NULL, &len);
326 /* w2k3 and below: E_FAIL and untouched len,
327 since w2k8: S_OK and needed size (excluding 0) */
328 ok( ((hr == S_OK) && (len == exactsize)) ||
329 ((hr == E_FAIL) && (len == maxlen)),
330 "NULL,max #%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
332 i++;
335 /* without a value in the registry, a default language is returned */
336 RegDeleteValue(hroot, acceptlanguage);
338 len = maxlen;
339 memset(buffer, '#', maxlen);
340 buffer[maxlen] = 0;
341 hr = pGetAcceptLanguagesA( buffer, &len);
342 ok( ((hr == S_OK) && (len == lstrlenA(language))),
343 "max: got 0x%x with %d and %s (expected S_OK with %d and '%s'\n",
344 hr, len, buffer, lstrlenA(language), language);
346 len = 2;
347 memset(buffer, '#', maxlen);
348 buffer[maxlen] = 0;
349 hr = pGetAcceptLanguagesA( buffer, &len);
350 ok( (((hr == S_OK) || (hr == E_INVALIDARG)) && !memcmp(buffer, language, len)) ||
351 ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len),
352 "=2: got 0x%x with %d and %s\n", hr, len, buffer);
354 len = 1;
355 memset(buffer, '#', maxlen);
356 buffer[maxlen] = 0;
357 hr = pGetAcceptLanguagesA( buffer, &len);
358 /* When the buffer is too small, win7_32 and w2k8_64 and above fail with
359 HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), other versions suceed
360 and return a partial 0 terminated result while other versions
361 fail with E_INVALIDARG and return a partial unterminated result */
362 ok( (((hr == S_OK) || (hr == E_INVALIDARG)) && !memcmp(buffer, language, len)) ||
363 ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len),
364 "=1: got 0x%x with %d and %s\n", hr, len, buffer);
366 len = 0;
367 memset(buffer, '#', maxlen);
368 buffer[maxlen] = 0;
369 hr = pGetAcceptLanguagesA( buffer, &len);
370 /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG */
371 ok((hr == E_FAIL) || (hr == E_INVALIDARG),
372 "got 0x%x (expected E_FAIL or E_INVALIDARG)\n", hr);
374 memset(buffer, '#', maxlen);
375 buffer[maxlen] = 0;
376 hr = pGetAcceptLanguagesA( buffer, NULL);
377 /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG */
378 ok((hr == E_FAIL) || (hr == E_INVALIDARG),
379 "got 0x%x (expected E_FAIL or E_INVALIDARG)\n", hr);
382 hr = pGetAcceptLanguagesA( NULL, NULL);
383 /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG */
384 ok((hr == E_FAIL) || (hr == E_INVALIDARG),
385 "got 0x%x (expected E_FAIL or E_INVALIDARG)\n", hr);
387 restore_original:
388 if (!res_query) {
389 len = lstrlenA(original);
390 lres = RegSetValueExA(hroot, acceptlanguage, 0, REG_SZ, (const BYTE *) original, len ? len + 1: 0);
391 ok(!lres, "RegSetValueEx(%s) failed: %d\n", original, lres);
393 else
395 RegDeleteValue(hroot, acceptlanguage);
397 RegCloseKey(hroot);
400 static void test_SHSearchMapInt(void)
402 int keys[8], values[8];
403 int i = 0;
405 if (!pSHSearchMapInt)
406 return;
408 memset(keys, 0, sizeof(keys));
409 memset(values, 0, sizeof(values));
410 keys[0] = 99; values[0] = 101;
412 /* NULL key/value lists crash native, so skip testing them */
414 /* 1 element */
415 i = pSHSearchMapInt(keys, values, 1, keys[0]);
416 ok(i == values[0], "Len 1, expected %d, got %d\n", values[0], i);
418 /* Key doesn't exist */
419 i = pSHSearchMapInt(keys, values, 1, 100);
420 ok(i == -1, "Len 1 - bad key, expected -1, got %d\n", i);
422 /* Len = 0 => not found */
423 i = pSHSearchMapInt(keys, values, 0, keys[0]);
424 ok(i == -1, "Len 1 - passed len 0, expected -1, got %d\n", i);
426 /* 2 elements, len = 1 */
427 keys[1] = 98; values[1] = 102;
428 i = pSHSearchMapInt(keys, values, 1, keys[1]);
429 ok(i == -1, "Len 1 - array len 2, expected -1, got %d\n", i);
431 /* 2 elements, len = 2 */
432 i = pSHSearchMapInt(keys, values, 2, keys[1]);
433 ok(i == values[1], "Len 2, expected %d, got %d\n", values[1], i);
435 /* Searches forward */
436 keys[2] = 99; values[2] = 103;
437 i = pSHSearchMapInt(keys, values, 3, keys[0]);
438 ok(i == values[0], "Len 3, expected %d, got %d\n", values[0], i);
441 static void test_alloc_shared(void)
443 DWORD procid;
444 HANDLE hmem;
445 int val;
446 int* p;
447 BOOL ret;
449 procid=GetCurrentProcessId();
450 hmem=pSHAllocShared(NULL,10,procid);
451 ok(hmem!=NULL,"SHAllocShared(NULL...) failed: %u\n", GetLastError());
452 ret = pSHFreeShared(hmem, procid);
453 ok( ret, "SHFreeShared failed: %u\n", GetLastError());
455 val=0x12345678;
456 hmem=pSHAllocShared(&val,4,procid);
457 ok(hmem!=NULL,"SHAllocShared(NULL...) failed: %u\n", GetLastError());
459 p=pSHLockShared(hmem,procid);
460 ok(p!=NULL,"SHLockShared failed: %u\n", GetLastError());
461 if (p!=NULL)
462 ok(*p==val,"Wrong value in shared memory: %d instead of %d\n",*p,val);
463 ret = pSHUnlockShared(p);
464 ok( ret, "SHUnlockShared failed: %u\n", GetLastError());
466 ret = pSHFreeShared(hmem, procid);
467 ok( ret, "SHFreeShared failed: %u\n", GetLastError());
470 static void test_fdsa(void)
472 typedef struct
474 DWORD num_items; /* Number of elements inserted */
475 void *mem; /* Ptr to array */
476 DWORD blocks_alloced; /* Number of elements allocated */
477 BYTE inc; /* Number of elements to grow by when we need to expand */
478 BYTE block_size; /* Size in bytes of an element */
479 BYTE flags; /* Flags */
480 } FDSA_info;
482 BOOL (WINAPI *pFDSA_Initialize)(DWORD block_size, DWORD inc, FDSA_info *info, void *mem,
483 DWORD init_blocks);
484 BOOL (WINAPI *pFDSA_Destroy)(FDSA_info *info);
485 DWORD (WINAPI *pFDSA_InsertItem)(FDSA_info *info, DWORD where, const void *block);
486 BOOL (WINAPI *pFDSA_DeleteItem)(FDSA_info *info, DWORD where);
488 FDSA_info info;
489 int block_size = 10, init_blocks = 4, inc = 2;
490 DWORD ret;
491 char *mem;
493 pFDSA_Initialize = (void *)GetProcAddress(hShlwapi, (LPSTR)208);
494 pFDSA_Destroy = (void *)GetProcAddress(hShlwapi, (LPSTR)209);
495 pFDSA_InsertItem = (void *)GetProcAddress(hShlwapi, (LPSTR)210);
496 pFDSA_DeleteItem = (void *)GetProcAddress(hShlwapi, (LPSTR)211);
498 mem = HeapAlloc(GetProcessHeap(), 0, block_size * init_blocks);
499 memset(&info, 0, sizeof(info));
501 ok(pFDSA_Initialize(block_size, inc, &info, mem, init_blocks), "FDSA_Initialize rets FALSE\n");
502 ok(info.num_items == 0, "num_items = %d\n", info.num_items);
503 ok(info.mem == mem, "mem = %p\n", info.mem);
504 ok(info.blocks_alloced == init_blocks, "blocks_alloced = %d\n", info.blocks_alloced);
505 ok(info.inc == inc, "inc = %d\n", info.inc);
506 ok(info.block_size == block_size, "block_size = %d\n", info.block_size);
507 ok(info.flags == 0, "flags = %d\n", info.flags);
509 ret = pFDSA_InsertItem(&info, 1234, "1234567890");
510 ok(ret == 0, "ret = %d\n", ret);
511 ok(info.num_items == 1, "num_items = %d\n", info.num_items);
512 ok(info.mem == mem, "mem = %p\n", info.mem);
513 ok(info.blocks_alloced == init_blocks, "blocks_alloced = %d\n", info.blocks_alloced);
514 ok(info.inc == inc, "inc = %d\n", info.inc);
515 ok(info.block_size == block_size, "block_size = %d\n", info.block_size);
516 ok(info.flags == 0, "flags = %d\n", info.flags);
518 ret = pFDSA_InsertItem(&info, 1234, "abcdefghij");
519 ok(ret == 1, "ret = %d\n", ret);
521 ret = pFDSA_InsertItem(&info, 1, "klmnopqrst");
522 ok(ret == 1, "ret = %d\n", ret);
524 ret = pFDSA_InsertItem(&info, 0, "uvwxyzABCD");
525 ok(ret == 0, "ret = %d\n", ret);
526 ok(info.mem == mem, "mem = %p\n", info.mem);
527 ok(info.flags == 0, "flags = %d\n", info.flags);
529 /* This next InsertItem will cause shlwapi to allocate its own mem buffer */
530 ret = pFDSA_InsertItem(&info, 0, "EFGHIJKLMN");
531 ok(ret == 0, "ret = %d\n", ret);
532 ok(info.mem != mem, "mem = %p\n", info.mem);
533 ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %d\n", info.blocks_alloced);
534 ok(info.flags == 0x1, "flags = %d\n", info.flags);
536 ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCD1234567890klmnopqrstabcdefghij", 50), "mem %s\n", (char*)info.mem);
538 ok(pFDSA_DeleteItem(&info, 2), "rets FALSE\n");
539 ok(info.mem != mem, "mem = %p\n", info.mem);
540 ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %d\n", info.blocks_alloced);
541 ok(info.flags == 0x1, "flags = %d\n", info.flags);
543 ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCDklmnopqrstabcdefghij", 40), "mem %s\n", (char*)info.mem);
545 ok(pFDSA_DeleteItem(&info, 3), "rets FALSE\n");
546 ok(info.mem != mem, "mem = %p\n", info.mem);
547 ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %d\n", info.blocks_alloced);
548 ok(info.flags == 0x1, "flags = %d\n", info.flags);
550 ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCDklmnopqrst", 30), "mem %s\n", (char*)info.mem);
552 ok(!pFDSA_DeleteItem(&info, 4), "does not ret FALSE\n");
554 /* As shlwapi has allocated memory internally, Destroy will ret FALSE */
555 ok(!pFDSA_Destroy(&info), "FDSA_Destroy does not ret FALSE\n");
558 /* When Initialize is called with inc = 0, set it to 1 */
559 ok(pFDSA_Initialize(block_size, 0, &info, mem, init_blocks), "FDSA_Initialize rets FALSE\n");
560 ok(info.inc == 1, "inc = %d\n", info.inc);
562 /* This time, because shlwapi hasn't had to allocate memory
563 internally, Destroy rets non-zero */
564 ok(pFDSA_Destroy(&info), "FDSA_Destroy rets FALSE\n");
567 HeapFree(GetProcessHeap(), 0, mem);
571 typedef struct SHELL_USER_SID {
572 SID_IDENTIFIER_AUTHORITY sidAuthority;
573 DWORD dwUserGroupID;
574 DWORD dwUserID;
575 } SHELL_USER_SID, *PSHELL_USER_SID;
576 typedef struct SHELL_USER_PERMISSION {
577 SHELL_USER_SID susID;
578 DWORD dwAccessType;
579 BOOL fInherit;
580 DWORD dwAccessMask;
581 DWORD dwInheritMask;
582 DWORD dwInheritAccessMask;
583 } SHELL_USER_PERMISSION, *PSHELL_USER_PERMISSION;
584 static void test_GetShellSecurityDescriptor(void)
586 SHELL_USER_PERMISSION supCurrentUserFull = {
587 { {SECURITY_NULL_SID_AUTHORITY}, 0, 0 },
588 ACCESS_ALLOWED_ACE_TYPE, FALSE,
589 GENERIC_ALL, 0, 0 };
590 #define MY_INHERITANCE 0xBE /* invalid value to proof behavior */
591 SHELL_USER_PERMISSION supEveryoneDenied = {
592 { {SECURITY_WORLD_SID_AUTHORITY}, SECURITY_WORLD_RID, 0 },
593 ACCESS_DENIED_ACE_TYPE, TRUE,
594 GENERIC_WRITE, MY_INHERITANCE | 0xDEADBA00, GENERIC_READ };
595 PSHELL_USER_PERMISSION rgsup[2] = {
596 &supCurrentUserFull, &supEveryoneDenied,
598 SECURITY_DESCRIPTOR* psd;
599 SECURITY_DESCRIPTOR* (WINAPI*pGetShellSecurityDescriptor)(PSHELL_USER_PERMISSION*,int);
600 void *pChrCmpIW = GetProcAddress(hShlwapi, "ChrCmpIW");
602 pGetShellSecurityDescriptor=(void*)GetProcAddress(hShlwapi,(char*)475);
604 if(!pGetShellSecurityDescriptor)
606 win_skip("GetShellSecurityDescriptor not available\n");
607 return;
610 if(pChrCmpIW && pChrCmpIW == pGetShellSecurityDescriptor) /* win2k */
612 win_skip("Skipping for GetShellSecurityDescriptor, same ordinal used for ChrCmpIW\n");
613 return;
616 psd = pGetShellSecurityDescriptor(NULL, 2);
617 ok(psd==NULL ||
618 broken(psd==INVALID_HANDLE_VALUE), /* IE5 */
619 "GetShellSecurityDescriptor should fail\n");
620 psd = pGetShellSecurityDescriptor(rgsup, 0);
621 ok(psd==NULL, "GetShellSecurityDescriptor should fail, got %p\n", psd);
623 SetLastError(0xdeadbeef);
624 psd = pGetShellSecurityDescriptor(rgsup, 2);
625 if (psd == NULL && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
627 /* The previous calls to GetShellSecurityDescriptor don't set the last error */
628 win_skip("GetShellSecurityDescriptor is not implemented\n");
629 return;
631 if (psd == INVALID_HANDLE_VALUE)
633 win_skip("GetShellSecurityDescriptor is broken on IE5\n");
634 return;
636 ok(psd!=NULL, "GetShellSecurityDescriptor failed\n");
637 if (psd!=NULL)
639 BOOL bHasDacl = FALSE, bDefaulted, ret;
640 PACL pAcl;
641 DWORD dwRev;
642 SECURITY_DESCRIPTOR_CONTROL control;
644 ok(IsValidSecurityDescriptor(psd), "returned value is not valid SD\n");
646 ret = GetSecurityDescriptorControl(psd, &control, &dwRev);
647 ok(ret, "GetSecurityDescriptorControl failed with error %u\n", GetLastError());
648 ok(0 == (control & SE_SELF_RELATIVE), "SD should be absolute\n");
650 ret = GetSecurityDescriptorDacl(psd, &bHasDacl, &pAcl, &bDefaulted);
651 ok(ret, "GetSecurityDescriptorDacl failed with error %u\n", GetLastError());
653 ok(bHasDacl, "SD has no DACL\n");
654 if (bHasDacl)
656 ok(!bDefaulted, "DACL should not be defaulted\n");
658 ok(pAcl != NULL, "NULL DACL!\n");
659 if (pAcl != NULL)
661 ACL_SIZE_INFORMATION asiSize;
663 ok(IsValidAcl(pAcl), "DACL is not valid\n");
665 ret = GetAclInformation(pAcl, &asiSize, sizeof(asiSize), AclSizeInformation);
666 ok(ret, "GetAclInformation failed with error %u\n", GetLastError());
668 ok(asiSize.AceCount == 3, "Incorrect number of ACEs: %d entries\n", asiSize.AceCount);
669 if (asiSize.AceCount == 3)
671 ACCESS_ALLOWED_ACE *paaa; /* will use for DENIED too */
673 ret = GetAce(pAcl, 0, (LPVOID*)&paaa);
674 ok(ret, "GetAce failed with error %u\n", GetLastError());
675 ok(paaa->Header.AceType == ACCESS_ALLOWED_ACE_TYPE,
676 "Invalid ACE type %d\n", paaa->Header.AceType);
677 ok(paaa->Header.AceFlags == 0, "Invalid ACE flags %x\n", paaa->Header.AceFlags);
678 ok(paaa->Mask == GENERIC_ALL, "Invalid ACE mask %x\n", paaa->Mask);
680 ret = GetAce(pAcl, 1, (LPVOID*)&paaa);
681 ok(ret, "GetAce failed with error %u\n", GetLastError());
682 ok(paaa->Header.AceType == ACCESS_DENIED_ACE_TYPE,
683 "Invalid ACE type %d\n", paaa->Header.AceType);
684 /* first one of two ACEs generated from inheritable entry - without inheritance */
685 ok(paaa->Header.AceFlags == 0, "Invalid ACE flags %x\n", paaa->Header.AceFlags);
686 ok(paaa->Mask == GENERIC_WRITE, "Invalid ACE mask %x\n", paaa->Mask);
688 ret = GetAce(pAcl, 2, (LPVOID*)&paaa);
689 ok(ret, "GetAce failed with error %u\n", GetLastError());
690 ok(paaa->Header.AceType == ACCESS_DENIED_ACE_TYPE,
691 "Invalid ACE type %d\n", paaa->Header.AceType);
692 /* second ACE - with inheritance */
693 ok(paaa->Header.AceFlags == MY_INHERITANCE,
694 "Invalid ACE flags %x\n", paaa->Header.AceFlags);
695 ok(paaa->Mask == GENERIC_READ, "Invalid ACE mask %x\n", paaa->Mask);
700 LocalFree(psd);
704 static void test_SHPackDispParams(void)
706 DISPPARAMS params;
707 VARIANT vars[10];
708 HRESULT hres;
710 if(!pSHPackDispParams)
711 win_skip("SHPackSidpParams not available\n");
713 memset(&params, 0xc0, sizeof(params));
714 memset(vars, 0xc0, sizeof(vars));
715 hres = pSHPackDispParams(&params, vars, 1, VT_I4, 0xdeadbeef);
716 ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres);
717 ok(params.cArgs == 1, "params.cArgs = %d\n", params.cArgs);
718 ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
719 ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
720 ok(params.rgvarg == vars, "params.rgvarg = %p\n", params.rgvarg);
721 ok(V_VT(vars) == VT_I4, "V_VT(var) = %d\n", V_VT(vars));
722 ok(V_I4(vars) == 0xdeadbeef, "failed %x\n", V_I4(vars));
724 memset(&params, 0xc0, sizeof(params));
725 hres = pSHPackDispParams(&params, NULL, 0, 0);
726 ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres);
727 ok(params.cArgs == 0, "params.cArgs = %d\n", params.cArgs);
728 ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
729 ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
730 ok(params.rgvarg == NULL, "params.rgvarg = %p\n", params.rgvarg);
732 memset(vars, 0xc0, sizeof(vars));
733 memset(&params, 0xc0, sizeof(params));
734 hres = pSHPackDispParams(&params, vars, 4, VT_BSTR, (void*)0xdeadbeef, VT_EMPTY, 10,
735 VT_I4, 100, VT_DISPATCH, (void*)0xdeadbeef);
736 ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres);
737 ok(params.cArgs == 4, "params.cArgs = %d\n", params.cArgs);
738 ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
739 ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
740 ok(params.rgvarg == vars, "params.rgvarg = %p\n", params.rgvarg);
741 ok(V_VT(vars) == VT_DISPATCH, "V_VT(vars[0]) = %x\n", V_VT(vars));
742 ok(V_I4(vars) == 0xdeadbeef, "V_I4(vars[0]) = %x\n", V_I4(vars));
743 ok(V_VT(vars+1) == VT_I4, "V_VT(vars[1]) = %d\n", V_VT(vars+1));
744 ok(V_I4(vars+1) == 100, "V_I4(vars[1]) = %x\n", V_I4(vars+1));
745 ok(V_VT(vars+2) == VT_I4, "V_VT(vars[2]) = %d\n", V_VT(vars+2));
746 ok(V_I4(vars+2) == 10, "V_I4(vars[2]) = %x\n", V_I4(vars+2));
747 ok(V_VT(vars+3) == VT_BSTR, "V_VT(vars[3]) = %d\n", V_VT(vars+3));
748 ok(V_BSTR(vars+3) == (void*)0xdeadbeef, "V_BSTR(vars[3]) = %p\n", V_BSTR(vars+3));
751 typedef struct _disp
753 IDispatch IDispatch_iface;
754 LONG refCount;
755 } Disp;
757 static inline Disp *impl_from_IDispatch(IDispatch *iface)
759 return CONTAINING_RECORD(iface, Disp, IDispatch_iface);
762 typedef struct _contain
764 IConnectionPointContainer IConnectionPointContainer_iface;
765 LONG refCount;
767 UINT ptCount;
768 IConnectionPoint **pt;
769 } Contain;
771 static inline Contain *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
773 return CONTAINING_RECORD(iface, Contain, IConnectionPointContainer_iface);
776 typedef struct _cntptn
778 IConnectionPoint IConnectionPoint_iface;
779 LONG refCount;
781 Contain *container;
782 GUID id;
783 UINT sinkCount;
784 IUnknown **sink;
785 } ConPt;
787 static inline ConPt *impl_from_IConnectionPoint(IConnectionPoint *iface)
789 return CONTAINING_RECORD(iface, ConPt, IConnectionPoint_iface);
792 typedef struct _enum
794 IEnumConnections IEnumConnections_iface;
795 LONG refCount;
797 UINT idx;
798 ConPt *pt;
799 } EnumCon;
801 static inline EnumCon *impl_from_IEnumConnections(IEnumConnections *iface)
803 return CONTAINING_RECORD(iface, EnumCon, IEnumConnections_iface);
806 typedef struct _enumpt
808 IEnumConnectionPoints IEnumConnectionPoints_iface;
809 LONG refCount;
811 int idx;
812 Contain *container;
813 } EnumPt;
815 static inline EnumPt *impl_from_IEnumConnectionPoints(IEnumConnectionPoints *iface)
817 return CONTAINING_RECORD(iface, EnumPt, IEnumConnectionPoints_iface);
821 static HRESULT WINAPI Disp_QueryInterface(
822 IDispatch* This,
823 REFIID riid,
824 void **ppvObject)
826 *ppvObject = NULL;
828 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDispatch))
830 *ppvObject = This;
833 if (*ppvObject)
835 IUnknown_AddRef(This);
836 return S_OK;
839 trace("no interface\n");
840 return E_NOINTERFACE;
843 static ULONG WINAPI Disp_AddRef(IDispatch* This)
845 Disp *iface = impl_from_IDispatch(This);
846 return InterlockedIncrement(&iface->refCount);
849 static ULONG WINAPI Disp_Release(IDispatch* This)
851 Disp *iface = impl_from_IDispatch(This);
852 ULONG ret;
854 ret = InterlockedDecrement(&iface->refCount);
855 if (ret == 0)
856 HeapFree(GetProcessHeap(),0,This);
857 return ret;
860 static HRESULT WINAPI Disp_GetTypeInfoCount(
861 IDispatch* This,
862 UINT *pctinfo)
864 return ERROR_SUCCESS;
867 static HRESULT WINAPI Disp_GetTypeInfo(
868 IDispatch* This,
869 UINT iTInfo,
870 LCID lcid,
871 ITypeInfo **ppTInfo)
873 return ERROR_SUCCESS;
876 static HRESULT WINAPI Disp_GetIDsOfNames(
877 IDispatch* This,
878 REFIID riid,
879 LPOLESTR *rgszNames,
880 UINT cNames,
881 LCID lcid,
882 DISPID *rgDispId)
884 return ERROR_SUCCESS;
887 static HRESULT WINAPI Disp_Invoke(
888 IDispatch* This,
889 DISPID dispIdMember,
890 REFIID riid,
891 LCID lcid,
892 WORD wFlags,
893 DISPPARAMS *pDispParams,
894 VARIANT *pVarResult,
895 EXCEPINFO *pExcepInfo,
896 UINT *puArgErr)
898 trace("%p %x %p %x %x %p %p %p %p\n",This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
900 ok(dispIdMember == 0xa0 || dispIdMember == 0xa1, "Unknown dispIdMember\n");
901 ok(pDispParams != NULL, "Invoked with NULL pDispParams\n");
902 ok(wFlags == DISPATCH_METHOD, "Wrong flags %x\n",wFlags);
903 ok(lcid == 0,"Wrong lcid %x\n",lcid);
904 if (dispIdMember == 0xa0)
906 ok(pDispParams->cArgs == 0, "params.cArgs = %d\n", pDispParams->cArgs);
907 ok(pDispParams->cNamedArgs == 0, "params.cNamedArgs = %d\n", pDispParams->cArgs);
908 ok(pDispParams->rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", pDispParams->rgdispidNamedArgs);
909 ok(pDispParams->rgvarg == NULL, "params.rgvarg = %p\n", pDispParams->rgvarg);
911 else if (dispIdMember == 0xa1)
913 ok(pDispParams->cArgs == 2, "params.cArgs = %d\n", pDispParams->cArgs);
914 ok(pDispParams->cNamedArgs == 0, "params.cNamedArgs = %d\n", pDispParams->cArgs);
915 ok(pDispParams->rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", pDispParams->rgdispidNamedArgs);
916 ok(V_VT(pDispParams->rgvarg) == VT_BSTR, "V_VT(var) = %d\n", V_VT(pDispParams->rgvarg));
917 ok(V_I4(pDispParams->rgvarg) == 0xdeadcafe , "failed %p\n", V_BSTR(pDispParams->rgvarg));
918 ok(V_VT(pDispParams->rgvarg+1) == VT_I4, "V_VT(var) = %d\n", V_VT(pDispParams->rgvarg+1));
919 ok(V_I4(pDispParams->rgvarg+1) == 0xdeadbeef, "failed %x\n", V_I4(pDispParams->rgvarg+1));
922 return ERROR_SUCCESS;
925 static const IDispatchVtbl disp_vtbl = {
926 Disp_QueryInterface,
927 Disp_AddRef,
928 Disp_Release,
930 Disp_GetTypeInfoCount,
931 Disp_GetTypeInfo,
932 Disp_GetIDsOfNames,
933 Disp_Invoke
936 static HRESULT WINAPI Enum_QueryInterface(
937 IEnumConnections* This,
938 REFIID riid,
939 void **ppvObject)
941 *ppvObject = NULL;
943 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumConnections))
945 *ppvObject = This;
948 if (*ppvObject)
950 IUnknown_AddRef(This);
951 return S_OK;
954 trace("no interface\n");
955 return E_NOINTERFACE;
958 static ULONG WINAPI Enum_AddRef(IEnumConnections* This)
960 EnumCon *iface = impl_from_IEnumConnections(This);
961 return InterlockedIncrement(&iface->refCount);
964 static ULONG WINAPI Enum_Release(IEnumConnections* This)
966 EnumCon *iface = impl_from_IEnumConnections(This);
967 ULONG ret;
969 ret = InterlockedDecrement(&iface->refCount);
970 if (ret == 0)
971 HeapFree(GetProcessHeap(),0,This);
972 return ret;
975 static HRESULT WINAPI Enum_Next(
976 IEnumConnections* This,
977 ULONG cConnections,
978 LPCONNECTDATA rgcd,
979 ULONG *pcFetched)
981 EnumCon *iface = impl_from_IEnumConnections(This);
983 if (cConnections > 0 && iface->idx < iface->pt->sinkCount)
985 rgcd->pUnk = iface->pt->sink[iface->idx];
986 IUnknown_AddRef(iface->pt->sink[iface->idx]);
987 rgcd->dwCookie=0xff;
988 if (pcFetched)
989 *pcFetched = 1;
990 iface->idx++;
991 return S_OK;
994 return E_FAIL;
997 static HRESULT WINAPI Enum_Skip(
998 IEnumConnections* This,
999 ULONG cConnections)
1001 return E_FAIL;
1004 static HRESULT WINAPI Enum_Reset(
1005 IEnumConnections* This)
1007 return E_FAIL;
1010 static HRESULT WINAPI Enum_Clone(
1011 IEnumConnections* This,
1012 IEnumConnections **ppEnum)
1014 return E_FAIL;
1017 static const IEnumConnectionsVtbl enum_vtbl = {
1019 Enum_QueryInterface,
1020 Enum_AddRef,
1021 Enum_Release,
1022 Enum_Next,
1023 Enum_Skip,
1024 Enum_Reset,
1025 Enum_Clone
1028 static HRESULT WINAPI ConPt_QueryInterface(
1029 IConnectionPoint* This,
1030 REFIID riid,
1031 void **ppvObject)
1033 *ppvObject = NULL;
1035 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IConnectionPoint))
1037 *ppvObject = This;
1040 if (*ppvObject)
1042 IUnknown_AddRef(This);
1043 return S_OK;
1046 trace("no interface\n");
1047 return E_NOINTERFACE;
1050 static ULONG WINAPI ConPt_AddRef(
1051 IConnectionPoint* This)
1053 ConPt *iface = impl_from_IConnectionPoint(This);
1054 return InterlockedIncrement(&iface->refCount);
1057 static ULONG WINAPI ConPt_Release(
1058 IConnectionPoint* This)
1060 ConPt *iface = impl_from_IConnectionPoint(This);
1061 ULONG ret;
1063 ret = InterlockedDecrement(&iface->refCount);
1064 if (ret == 0)
1066 if (iface->sinkCount > 0)
1068 int i;
1069 for (i = 0; i < iface->sinkCount; i++)
1071 if (iface->sink[i])
1072 IUnknown_Release(iface->sink[i]);
1074 HeapFree(GetProcessHeap(),0,iface->sink);
1076 HeapFree(GetProcessHeap(),0,This);
1078 return ret;
1081 static HRESULT WINAPI ConPt_GetConnectionInterface(
1082 IConnectionPoint* This,
1083 IID *pIID)
1085 static int i = 0;
1086 ConPt *iface = impl_from_IConnectionPoint(This);
1087 if (i==0)
1089 i++;
1090 return E_FAIL;
1092 else
1093 memcpy(pIID,&iface->id,sizeof(GUID));
1094 return S_OK;
1097 static HRESULT WINAPI ConPt_GetConnectionPointContainer(
1098 IConnectionPoint* This,
1099 IConnectionPointContainer **ppCPC)
1101 ConPt *iface = impl_from_IConnectionPoint(This);
1103 *ppCPC = &iface->container->IConnectionPointContainer_iface;
1104 return S_OK;
1107 static HRESULT WINAPI ConPt_Advise(
1108 IConnectionPoint* This,
1109 IUnknown *pUnkSink,
1110 DWORD *pdwCookie)
1112 ConPt *iface = impl_from_IConnectionPoint(This);
1114 if (iface->sinkCount == 0)
1115 iface->sink = HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown*));
1116 else
1117 iface->sink = HeapReAlloc(GetProcessHeap(),0,iface->sink,sizeof(IUnknown*)*(iface->sinkCount+1));
1118 iface->sink[iface->sinkCount] = pUnkSink;
1119 IUnknown_AddRef(pUnkSink);
1120 iface->sinkCount++;
1121 *pdwCookie = iface->sinkCount;
1122 return S_OK;
1125 static HRESULT WINAPI ConPt_Unadvise(
1126 IConnectionPoint* This,
1127 DWORD dwCookie)
1129 ConPt *iface = impl_from_IConnectionPoint(This);
1131 if (dwCookie > iface->sinkCount)
1132 return E_FAIL;
1133 else
1135 IUnknown_Release(iface->sink[dwCookie-1]);
1136 iface->sink[dwCookie-1] = NULL;
1138 return S_OK;
1141 static HRESULT WINAPI ConPt_EnumConnections(
1142 IConnectionPoint* This,
1143 IEnumConnections **ppEnum)
1145 EnumCon *ec;
1147 ec = HeapAlloc(GetProcessHeap(),0,sizeof(EnumCon));
1148 ec->IEnumConnections_iface.lpVtbl = &enum_vtbl;
1149 ec->refCount = 1;
1150 ec->pt = impl_from_IConnectionPoint(This);
1151 ec->idx = 0;
1152 *ppEnum = &ec->IEnumConnections_iface;
1154 return S_OK;
1157 static const IConnectionPointVtbl point_vtbl = {
1158 ConPt_QueryInterface,
1159 ConPt_AddRef,
1160 ConPt_Release,
1162 ConPt_GetConnectionInterface,
1163 ConPt_GetConnectionPointContainer,
1164 ConPt_Advise,
1165 ConPt_Unadvise,
1166 ConPt_EnumConnections
1169 static HRESULT WINAPI EnumPt_QueryInterface(
1170 IEnumConnectionPoints* This,
1171 REFIID riid,
1172 void **ppvObject)
1174 *ppvObject = NULL;
1176 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumConnectionPoints))
1178 *ppvObject = This;
1181 if (*ppvObject)
1183 IUnknown_AddRef(This);
1184 return S_OK;
1187 trace("no interface\n");
1188 return E_NOINTERFACE;
1191 static ULONG WINAPI EnumPt_AddRef(IEnumConnectionPoints* This)
1193 EnumPt *iface = impl_from_IEnumConnectionPoints(This);
1194 return InterlockedIncrement(&iface->refCount);
1197 static ULONG WINAPI EnumPt_Release(IEnumConnectionPoints* This)
1199 EnumPt *iface = impl_from_IEnumConnectionPoints(This);
1200 ULONG ret;
1202 ret = InterlockedDecrement(&iface->refCount);
1203 if (ret == 0)
1204 HeapFree(GetProcessHeap(),0,This);
1205 return ret;
1208 static HRESULT WINAPI EnumPt_Next(
1209 IEnumConnectionPoints* This,
1210 ULONG cConnections,
1211 IConnectionPoint **rgcd,
1212 ULONG *pcFetched)
1214 EnumPt *iface = impl_from_IEnumConnectionPoints(This);
1216 if (cConnections > 0 && iface->idx < iface->container->ptCount)
1218 *rgcd = iface->container->pt[iface->idx];
1219 IUnknown_AddRef(iface->container->pt[iface->idx]);
1220 if (pcFetched)
1221 *pcFetched = 1;
1222 iface->idx++;
1223 return S_OK;
1226 return E_FAIL;
1229 static HRESULT WINAPI EnumPt_Skip(
1230 IEnumConnectionPoints* This,
1231 ULONG cConnections)
1233 return E_FAIL;
1236 static HRESULT WINAPI EnumPt_Reset(
1237 IEnumConnectionPoints* This)
1239 return E_FAIL;
1242 static HRESULT WINAPI EnumPt_Clone(
1243 IEnumConnectionPoints* This,
1244 IEnumConnectionPoints **ppEnumPt)
1246 return E_FAIL;
1249 static const IEnumConnectionPointsVtbl enumpt_vtbl = {
1251 EnumPt_QueryInterface,
1252 EnumPt_AddRef,
1253 EnumPt_Release,
1254 EnumPt_Next,
1255 EnumPt_Skip,
1256 EnumPt_Reset,
1257 EnumPt_Clone
1260 static HRESULT WINAPI Contain_QueryInterface(
1261 IConnectionPointContainer* This,
1262 REFIID riid,
1263 void **ppvObject)
1265 *ppvObject = NULL;
1267 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IConnectionPointContainer))
1269 *ppvObject = This;
1272 if (*ppvObject)
1274 IUnknown_AddRef(This);
1275 return S_OK;
1278 trace("no interface\n");
1279 return E_NOINTERFACE;
1282 static ULONG WINAPI Contain_AddRef(
1283 IConnectionPointContainer* This)
1285 Contain *iface = impl_from_IConnectionPointContainer(This);
1286 return InterlockedIncrement(&iface->refCount);
1289 static ULONG WINAPI Contain_Release(
1290 IConnectionPointContainer* This)
1292 Contain *iface = impl_from_IConnectionPointContainer(This);
1293 ULONG ret;
1295 ret = InterlockedDecrement(&iface->refCount);
1296 if (ret == 0)
1298 if (iface->ptCount > 0)
1300 int i;
1301 for (i = 0; i < iface->ptCount; i++)
1302 IUnknown_Release(iface->pt[i]);
1303 HeapFree(GetProcessHeap(),0,iface->pt);
1305 HeapFree(GetProcessHeap(),0,This);
1307 return ret;
1310 static HRESULT WINAPI Contain_EnumConnectionPoints(
1311 IConnectionPointContainer* This,
1312 IEnumConnectionPoints **ppEnum)
1314 EnumPt *ec;
1316 ec = HeapAlloc(GetProcessHeap(),0,sizeof(EnumPt));
1317 ec->IEnumConnectionPoints_iface.lpVtbl = &enumpt_vtbl;
1318 ec->refCount = 1;
1319 ec->idx= 0;
1320 ec->container = impl_from_IConnectionPointContainer(This);
1321 *ppEnum = &ec->IEnumConnectionPoints_iface;
1323 return S_OK;
1326 static HRESULT WINAPI Contain_FindConnectionPoint(
1327 IConnectionPointContainer* This,
1328 REFIID riid,
1329 IConnectionPoint **ppCP)
1331 Contain *iface = impl_from_IConnectionPointContainer(This);
1332 ConPt *pt;
1334 if (!IsEqualIID(riid, &IID_NULL) || iface->ptCount ==0)
1336 pt = HeapAlloc(GetProcessHeap(),0,sizeof(ConPt));
1337 pt->IConnectionPoint_iface.lpVtbl = &point_vtbl;
1338 pt->refCount = 1;
1339 pt->sinkCount = 0;
1340 pt->sink = NULL;
1341 pt->container = iface;
1342 pt->id = IID_IDispatch;
1344 if (iface->ptCount == 0)
1345 iface->pt =HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown*));
1346 else
1347 iface->pt = HeapReAlloc(GetProcessHeap(),0,iface->pt,sizeof(IUnknown*)*(iface->ptCount+1));
1348 iface->pt[iface->ptCount] = &pt->IConnectionPoint_iface;
1349 iface->ptCount++;
1351 *ppCP = &pt->IConnectionPoint_iface;
1353 else
1355 *ppCP = iface->pt[0];
1356 IUnknown_AddRef((IUnknown*)*ppCP);
1359 return S_OK;
1362 static const IConnectionPointContainerVtbl contain_vtbl = {
1363 Contain_QueryInterface,
1364 Contain_AddRef,
1365 Contain_Release,
1367 Contain_EnumConnectionPoints,
1368 Contain_FindConnectionPoint
1371 static void test_IConnectionPoint(void)
1373 HRESULT rc;
1374 ULONG ref;
1375 IConnectionPoint *point;
1376 Contain *container;
1377 Disp *dispatch;
1378 DWORD cookie = 0xffffffff;
1379 DISPPARAMS params;
1380 VARIANT vars[10];
1382 if (!pIConnectionPoint_SimpleInvoke || !pConnectToConnectionPoint)
1384 win_skip("IConnectionPoint Apis not present\n");
1385 return;
1388 container = HeapAlloc(GetProcessHeap(),0,sizeof(Contain));
1389 container->IConnectionPointContainer_iface.lpVtbl = &contain_vtbl;
1390 container->refCount = 1;
1391 container->ptCount = 0;
1392 container->pt = NULL;
1394 dispatch = HeapAlloc(GetProcessHeap(),0,sizeof(Disp));
1395 dispatch->IDispatch_iface.lpVtbl = &disp_vtbl;
1396 dispatch->refCount = 1;
1398 rc = pConnectToConnectionPoint((IUnknown*)dispatch, &IID_NULL, TRUE, (IUnknown*)container, &cookie, &point);
1399 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1400 ok(point != NULL, "returned ConnectionPoint is NULL\n");
1401 ok(cookie != 0xffffffff, "invalid cookie returned\n");
1403 rc = pIConnectionPoint_SimpleInvoke(point,0xa0,NULL);
1404 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1406 if (pSHPackDispParams)
1408 memset(&params, 0xc0, sizeof(params));
1409 memset(vars, 0xc0, sizeof(vars));
1410 rc = pSHPackDispParams(&params, vars, 2, VT_I4, 0xdeadbeef, VT_BSTR, 0xdeadcafe);
1411 ok(rc == S_OK, "SHPackDispParams failed: %08x\n", rc);
1413 rc = pIConnectionPoint_SimpleInvoke(point,0xa1,&params);
1414 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1416 else
1417 win_skip("pSHPackDispParams not present\n");
1419 rc = pConnectToConnectionPoint(NULL, &IID_NULL, FALSE, (IUnknown*)container, &cookie, NULL);
1420 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1422 /* MSDN says this should be required but it crashs on XP
1423 IUnknown_Release(point);
1425 ref = IUnknown_Release((IUnknown*)container);
1426 ok(ref == 0, "leftover IConnectionPointContainer reference %i\n",ref);
1427 ref = IUnknown_Release((IUnknown*)dispatch);
1428 ok(ref == 0, "leftover IDispatch reference %i\n",ref);
1431 typedef struct _propbag
1433 IPropertyBag IPropertyBag_iface;
1434 LONG refCount;
1436 } PropBag;
1438 static inline PropBag *impl_from_IPropertyBag(IPropertyBag *iface)
1440 return CONTAINING_RECORD(iface, PropBag, IPropertyBag_iface);
1444 static HRESULT WINAPI Prop_QueryInterface(
1445 IPropertyBag* This,
1446 REFIID riid,
1447 void **ppvObject)
1449 *ppvObject = NULL;
1451 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPropertyBag))
1453 *ppvObject = This;
1456 if (*ppvObject)
1458 IUnknown_AddRef(This);
1459 return S_OK;
1462 trace("no interface\n");
1463 return E_NOINTERFACE;
1466 static ULONG WINAPI Prop_AddRef(
1467 IPropertyBag* This)
1469 PropBag *iface = impl_from_IPropertyBag(This);
1470 return InterlockedIncrement(&iface->refCount);
1473 static ULONG WINAPI Prop_Release(
1474 IPropertyBag* This)
1476 PropBag *iface = impl_from_IPropertyBag(This);
1477 ULONG ret;
1479 ret = InterlockedDecrement(&iface->refCount);
1480 if (ret == 0)
1481 HeapFree(GetProcessHeap(),0,This);
1482 return ret;
1485 static HRESULT WINAPI Prop_Read(
1486 IPropertyBag* This,
1487 LPCOLESTR pszPropName,
1488 VARIANT *pVar,
1489 IErrorLog *pErrorLog)
1491 V_VT(pVar) = VT_BLOB|VT_BYREF;
1492 V_BYREF(pVar) = (LPVOID)0xdeadcafe;
1493 return S_OK;
1496 static HRESULT WINAPI Prop_Write(
1497 IPropertyBag* This,
1498 LPCOLESTR pszPropName,
1499 VARIANT *pVar)
1501 return S_OK;
1505 static const IPropertyBagVtbl prop_vtbl = {
1506 Prop_QueryInterface,
1507 Prop_AddRef,
1508 Prop_Release,
1510 Prop_Read,
1511 Prop_Write
1514 static void test_SHPropertyBag_ReadLONG(void)
1516 PropBag *pb;
1517 HRESULT rc;
1518 LONG out;
1519 static const WCHAR szName1[] = {'n','a','m','e','1',0};
1521 if (!pSHPropertyBag_ReadLONG)
1523 win_skip("SHPropertyBag_ReadLONG not present\n");
1524 return;
1527 pb = HeapAlloc(GetProcessHeap(),0,sizeof(PropBag));
1528 pb->refCount = 1;
1529 pb->IPropertyBag_iface.lpVtbl = &prop_vtbl;
1531 out = 0xfeedface;
1532 rc = pSHPropertyBag_ReadLONG(NULL, szName1, &out);
1533 ok(rc == E_INVALIDARG || broken(rc == 0), "incorrect return %x\n",rc);
1534 ok(out == 0xfeedface, "value should not have changed\n");
1535 rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, NULL, &out);
1536 ok(rc == E_INVALIDARG || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
1537 ok(out == 0xfeedface, "value should not have changed\n");
1538 rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, szName1, NULL);
1539 ok(rc == E_INVALIDARG || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
1540 ok(out == 0xfeedface, "value should not have changed\n");
1541 rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, szName1, &out);
1542 ok(rc == DISP_E_BADVARTYPE || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
1543 ok(out == 0xfeedface || broken(out == 0xfeedfa00), "value should not have changed %x\n",out);
1544 IUnknown_Release((IUnknown*)pb);
1549 static void test_SHSetWindowBits(void)
1551 HWND hwnd;
1552 DWORD style, styleold;
1553 WNDCLASSA clsA;
1555 if(!pSHSetWindowBits)
1557 win_skip("SHSetWindowBits is not available\n");
1558 return;
1561 clsA.style = 0;
1562 clsA.lpfnWndProc = DefWindowProcA;
1563 clsA.cbClsExtra = 0;
1564 clsA.cbWndExtra = 0;
1565 clsA.hInstance = GetModuleHandleA(NULL);
1566 clsA.hIcon = 0;
1567 clsA.hCursor = LoadCursorA(0, IDC_ARROW);
1568 clsA.hbrBackground = NULL;
1569 clsA.lpszMenuName = NULL;
1570 clsA.lpszClassName = "Shlwapi test class";
1571 RegisterClassA(&clsA);
1573 hwnd = CreateWindowA("Shlwapi test class", "Test", WS_VISIBLE, 0, 0, 100, 100,
1574 NULL, NULL, GetModuleHandle(NULL), 0);
1575 ok(IsWindow(hwnd), "failed to create window\n");
1577 /* null window */
1578 SetLastError(0xdeadbeef);
1579 style = pSHSetWindowBits(NULL, GWL_STYLE, 0, 0);
1580 ok(style == 0, "expected 0 retval, got %d\n", style);
1581 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
1582 broken(GetLastError() == 0xdeadbeef), /* Win9x/WinMe */
1583 "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
1585 /* zero mask, zero flags */
1586 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1587 style = pSHSetWindowBits(hwnd, GWL_STYLE, 0, 0);
1588 ok(styleold == style, "expected old style\n");
1589 ok(styleold == GetWindowLongA(hwnd, GWL_STYLE), "expected to keep old style\n");
1591 /* test mask */
1592 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1593 ok(styleold & WS_VISIBLE, "expected WS_VISIBLE\n");
1594 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1596 ok(style == styleold, "expected previous style, got %x\n", style);
1597 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1599 /* test mask, unset style bit used */
1600 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1601 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1602 ok(style == styleold, "expected previous style, got %x\n", style);
1603 ok(styleold == GetWindowLongA(hwnd, GWL_STYLE), "expected to keep old style\n");
1605 /* set back with flags */
1606 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1607 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, WS_VISIBLE);
1608 ok(style == styleold, "expected previous style, got %x\n", style);
1609 ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "expected updated style\n");
1611 /* reset and try to set without a mask */
1612 pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1613 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1614 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1615 style = pSHSetWindowBits(hwnd, GWL_STYLE, 0, WS_VISIBLE);
1616 ok(style == styleold, "expected previous style, got %x\n", style);
1617 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1619 DestroyWindow(hwnd);
1621 UnregisterClassA("Shlwapi test class", GetModuleHandleA(NULL));
1624 static void test_SHFormatDateTimeA(void)
1626 FILETIME UNALIGNED filetime;
1627 CHAR buff[100], buff2[100], buff3[100];
1628 SYSTEMTIME st;
1629 DWORD flags;
1630 INT ret;
1632 if(!pSHFormatDateTimeA)
1634 win_skip("pSHFormatDateTimeA isn't available\n");
1635 return;
1638 if (0)
1640 /* crashes on native */
1641 pSHFormatDateTimeA(NULL, NULL, NULL, 0);
1644 GetLocalTime(&st);
1645 SystemTimeToFileTime(&st, &filetime);
1646 /* SHFormatDateTime expects input as utc */
1647 LocalFileTimeToFileTime(&filetime, &filetime);
1649 /* no way to get required buffer length here */
1650 SetLastError(0xdeadbeef);
1651 ret = pSHFormatDateTimeA(&filetime, NULL, NULL, 0);
1652 ok(ret == 0, "got %d\n", ret);
1653 ok(GetLastError() == 0xdeadbeef || broken(GetLastError() == ERROR_SUCCESS /* Win7 */),
1654 "expected 0xdeadbeef, got %d\n", GetLastError());
1656 SetLastError(0xdeadbeef);
1657 buff[0] = 'a'; buff[1] = 0;
1658 ret = pSHFormatDateTimeA(&filetime, NULL, buff, 0);
1659 ok(ret == 0, "got %d\n", ret);
1660 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1661 ok(buff[0] == 'a', "expected same string, got %s\n", buff);
1663 /* flags needs to have FDTF_NOAUTOREADINGORDER for these tests to succeed on Vista+ */
1665 /* all combinations documented as invalid succeeded */
1666 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTTIME | FDTF_LONGTIME;
1667 SetLastError(0xdeadbeef);
1668 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1669 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1670 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1672 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_LONGDATE;
1673 SetLastError(0xdeadbeef);
1674 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1675 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1676 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1678 flags = FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE;
1679 SetLastError(0xdeadbeef);
1680 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1681 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1682 ok(GetLastError() == 0xdeadbeef ||
1683 broken(GetLastError() == ERROR_INVALID_FLAGS), /* Win9x/WinMe */
1684 "expected 0xdeadbeef, got %d\n", GetLastError());
1686 /* now check returned strings */
1687 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTTIME;
1688 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1689 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1690 ret = GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff2, sizeof(buff2));
1691 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1692 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1694 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGTIME;
1695 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1696 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1697 ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2));
1698 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1699 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1701 /* both time flags */
1702 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGTIME | FDTF_SHORTTIME;
1703 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1704 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1705 ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2));
1706 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1707 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1709 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE;
1710 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1711 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1712 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1713 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1714 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1716 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE;
1717 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1718 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1719 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1720 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1721 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1723 /* both date flags */
1724 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_SHORTDATE;
1725 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1726 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1727 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1728 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1729 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1731 /* various combinations of date/time flags */
1732 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_SHORTTIME;
1733 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1734 ok(ret == lstrlenA(buff)+1, "got %d, length %d\n", ret, lstrlenA(buff)+1);
1735 ret = GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3));
1736 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1737 ok(lstrcmpA(buff3, buff + lstrlenA(buff) - lstrlenA(buff3)) == 0,
1738 "expected (%s), got (%s) for time part\n",
1739 buff3, buff + lstrlenA(buff) - lstrlenA(buff3));
1740 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1741 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1742 buff[lstrlenA(buff2)] = '\0';
1743 ok(lstrcmpA(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1744 buff2, buff);
1746 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_LONGTIME;
1747 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1748 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1749 ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3));
1750 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1751 ok(lstrcmpA(buff3, buff + lstrlenA(buff) - lstrlenA(buff3)) == 0,
1752 "expected (%s), got (%s) for time part\n",
1753 buff3, buff + lstrlenA(buff) - lstrlenA(buff3));
1754 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1755 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1756 buff[lstrlenA(buff2)] = '\0';
1757 ok(lstrcmpA(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1758 buff2, buff);
1760 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_SHORTTIME;
1761 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1762 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1763 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1764 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1765 strcat(buff2, " ");
1766 ret = GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3));
1767 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1768 strcat(buff2, buff3);
1769 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1771 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_LONGTIME;
1772 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1773 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1774 ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1775 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1776 strcat(buff2, " ");
1777 ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3));
1778 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1779 strcat(buff2, buff3);
1780 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1783 static void test_SHFormatDateTimeW(void)
1785 FILETIME UNALIGNED filetime;
1786 WCHAR buff[100], buff2[100], buff3[100], *p1, *p2;
1787 SYSTEMTIME st;
1788 DWORD flags;
1789 INT ret;
1790 static const WCHAR spaceW[] = {' ',0};
1791 #define UNICODE_LTR_MARK 0x200e
1793 if(!pSHFormatDateTimeW)
1795 win_skip("pSHFormatDateTimeW isn't available\n");
1796 return;
1799 if (0)
1801 /* crashes on native */
1802 pSHFormatDateTimeW(NULL, NULL, NULL, 0);
1805 GetLocalTime(&st);
1806 SystemTimeToFileTime(&st, &filetime);
1807 /* SHFormatDateTime expects input as utc */
1808 LocalFileTimeToFileTime(&filetime, &filetime);
1810 /* no way to get required buffer length here */
1811 SetLastError(0xdeadbeef);
1812 ret = pSHFormatDateTimeW(&filetime, NULL, NULL, 0);
1813 ok(ret == 0, "expected 0, got %d\n", ret);
1814 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1816 SetLastError(0xdeadbeef);
1817 buff[0] = 'a'; buff[1] = 0;
1818 ret = pSHFormatDateTimeW(&filetime, NULL, buff, 0);
1819 ok(ret == 0, "expected 0, got %d\n", ret);
1820 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1821 ok(buff[0] == 'a', "expected same string\n");
1823 /* all combinations documented as invalid succeeded */
1824 flags = FDTF_SHORTTIME | FDTF_LONGTIME;
1825 SetLastError(0xdeadbeef);
1826 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1827 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1828 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1829 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1831 flags = FDTF_SHORTDATE | FDTF_LONGDATE;
1832 SetLastError(0xdeadbeef);
1833 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1834 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1835 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1836 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1838 flags = FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE;
1839 SetLastError(0xdeadbeef);
1840 buff[0] = 0; /* NT4 doesn't clear the buffer on failure */
1841 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1842 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1843 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1844 ok(GetLastError() == 0xdeadbeef ||
1845 broken(GetLastError() == ERROR_INVALID_FLAGS), /* Win9x/WinMe/NT4 */
1846 "expected 0xdeadbeef, got %d\n", GetLastError());
1848 /* now check returned strings */
1849 flags = FDTF_SHORTTIME;
1850 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1851 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1852 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1853 SetLastError(0xdeadbeef);
1854 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1855 if (ret == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1857 win_skip("Needed W-functions are not implemented\n");
1858 return;
1860 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1861 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1863 flags = FDTF_LONGTIME;
1864 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1865 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1866 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1867 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1868 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1869 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1871 /* both time flags */
1872 flags = FDTF_LONGTIME | FDTF_SHORTTIME;
1873 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1874 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1875 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1876 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1877 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1878 ok(lstrcmpW(buff, buff2) == 0, "expected equal string\n");
1880 flags = FDTF_SHORTDATE;
1881 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1882 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1883 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1884 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1885 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1886 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1888 flags = FDTF_LONGDATE;
1889 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1890 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1891 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1892 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1893 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1894 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1896 /* both date flags */
1897 flags = FDTF_LONGDATE | FDTF_SHORTDATE;
1898 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1899 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1900 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1901 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1902 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1903 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1905 /* various combinations of date/time flags */
1906 flags = FDTF_LONGDATE | FDTF_SHORTTIME;
1907 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1908 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1909 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1910 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1911 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1912 ok(lstrcmpW(buff3, buff + lstrlenW(buff) - lstrlenW(buff3)) == 0,
1913 "expected (%s), got (%s) for time part\n",
1914 wine_dbgstr_w(buff3), wine_dbgstr_w(buff + lstrlenW(buff) - lstrlenW(buff3)));
1915 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1916 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1917 p1 = buff;
1918 p2 = buff2;
1919 while (*p2 != '\0')
1921 while (*p1 == UNICODE_LTR_MARK)
1922 p1++;
1923 while (*p2 == UNICODE_LTR_MARK)
1924 p2++;
1925 p1++;
1926 p2++;
1928 *p1 = '\0';
1929 ok(lstrcmpW(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1930 wine_dbgstr_w(buff2), wine_dbgstr_w(buff));
1932 flags = FDTF_LONGDATE | FDTF_LONGTIME;
1933 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1934 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1935 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1936 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1937 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1938 ok(lstrcmpW(buff3, buff + lstrlenW(buff) - lstrlenW(buff3)) == 0,
1939 "expected (%s), got (%s) for time part\n",
1940 wine_dbgstr_w(buff3), wine_dbgstr_w(buff + lstrlenW(buff) - lstrlenW(buff3)));
1941 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1942 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1943 p1 = buff;
1944 p2 = buff2;
1945 while (*p2 != '\0')
1947 while (*p1 == UNICODE_LTR_MARK)
1948 p1++;
1949 while (*p2 == UNICODE_LTR_MARK)
1950 p2++;
1951 p1++;
1952 p2++;
1954 *p1 = '\0';
1955 ok(lstrcmpW(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1956 wine_dbgstr_w(buff2), wine_dbgstr_w(buff));
1958 flags = FDTF_SHORTDATE | FDTF_SHORTTIME;
1959 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1960 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1961 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1962 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1963 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1964 lstrcatW(buff2, spaceW);
1965 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1966 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1967 lstrcatW(buff2, buff3);
1968 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1970 flags = FDTF_SHORTDATE | FDTF_LONGTIME;
1971 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1972 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1973 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1974 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1975 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1976 lstrcatW(buff2, spaceW);
1977 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1978 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1979 lstrcatW(buff2, buff3);
1980 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1983 static void test_SHGetObjectCompatFlags(void)
1985 struct compat_value {
1986 CHAR nameA[30];
1987 DWORD value;
1990 struct compat_value values[] = {
1991 { "OTNEEDSSFCACHE", 0x1 },
1992 { "NO_WEBVIEW", 0x2 },
1993 { "UNBINDABLE", 0x4 },
1994 { "PINDLL", 0x8 },
1995 { "NEEDSFILESYSANCESTOR", 0x10 },
1996 { "NOTAFILESYSTEM", 0x20 },
1997 { "CTXMENU_NOVERBS", 0x40 },
1998 { "CTXMENU_LIMITEDQI", 0x80 },
1999 { "COCREATESHELLFOLDERONLY", 0x100 },
2000 { "NEEDSSTORAGEANCESTOR", 0x200 },
2001 { "NOLEGACYWEBVIEW", 0x400 },
2002 { "CTXMENU_XPQCMFLAGS", 0x1000 },
2003 { "NOIPROPERTYSTORE", 0x2000 }
2006 static const char compat_path[] = "Software\\Microsoft\\Windows\\CurrentVersion\\ShellCompatibility\\Objects";
2007 void *pColorAdjustLuma = GetProcAddress(hShlwapi, "ColorAdjustLuma");
2008 CHAR keyA[39]; /* {CLSID} */
2009 HKEY root;
2010 DWORD ret;
2011 int i;
2013 if (!pSHGetObjectCompatFlags)
2015 win_skip("SHGetObjectCompatFlags isn't available\n");
2016 return;
2019 if (pColorAdjustLuma && pColorAdjustLuma == pSHGetObjectCompatFlags) /* win2k */
2021 win_skip("Skipping SHGetObjectCompatFlags, same ordinal used for ColorAdjustLuma\n");
2022 return;
2025 /* null args */
2026 ret = pSHGetObjectCompatFlags(NULL, NULL);
2027 ok(ret == 0, "got %d\n", ret);
2029 ret = RegOpenKeyA(HKEY_LOCAL_MACHINE, compat_path, &root);
2030 if (ret != ERROR_SUCCESS)
2032 skip("No compatibility class data found\n");
2033 return;
2036 for (i = 0; RegEnumKeyA(root, i, keyA, sizeof(keyA)) == ERROR_SUCCESS; i++)
2038 HKEY clsid_key;
2040 if (RegOpenKeyA(root, keyA, &clsid_key) == ERROR_SUCCESS)
2042 CHAR valueA[30];
2043 DWORD expected = 0, got, length = sizeof(valueA);
2044 CLSID clsid;
2045 int v;
2047 for (v = 0; RegEnumValueA(clsid_key, v, valueA, &length, NULL, NULL, NULL, NULL) == ERROR_SUCCESS; v++)
2049 int j;
2051 for (j = 0; j < sizeof(values)/sizeof(struct compat_value); j++)
2052 if (lstrcmpA(values[j].nameA, valueA) == 0)
2054 expected |= values[j].value;
2055 break;
2058 length = sizeof(valueA);
2061 pGUIDFromStringA(keyA, &clsid);
2062 got = pSHGetObjectCompatFlags(NULL, &clsid);
2063 ok(got == expected, "got 0x%08x, expected 0x%08x. Key %s\n", got, expected, keyA);
2065 RegCloseKey(clsid_key);
2069 RegCloseKey(root);
2072 typedef struct {
2073 IOleCommandTarget IOleCommandTarget_iface;
2074 LONG ref;
2075 } IOleCommandTargetImpl;
2077 static inline IOleCommandTargetImpl *impl_from_IOleCommandTarget(IOleCommandTarget *iface)
2079 return CONTAINING_RECORD(iface, IOleCommandTargetImpl, IOleCommandTarget_iface);
2082 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl;
2084 static IOleCommandTarget* IOleCommandTargetImpl_Construct(void)
2086 IOleCommandTargetImpl *obj;
2088 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2089 obj->IOleCommandTarget_iface.lpVtbl = &IOleCommandTargetImpl_Vtbl;
2090 obj->ref = 1;
2092 return &obj->IOleCommandTarget_iface;
2095 static HRESULT WINAPI IOleCommandTargetImpl_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppvObj)
2097 IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface);
2099 if (IsEqualIID(riid, &IID_IUnknown) ||
2100 IsEqualIID(riid, &IID_IOleCommandTarget))
2102 *ppvObj = This;
2105 if(*ppvObj)
2107 IUnknown_AddRef(iface);
2108 return S_OK;
2111 return E_NOINTERFACE;
2114 static ULONG WINAPI IOleCommandTargetImpl_AddRef(IOleCommandTarget *iface)
2116 IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface);
2117 return InterlockedIncrement(&This->ref);
2120 static ULONG WINAPI IOleCommandTargetImpl_Release(IOleCommandTarget *iface)
2122 IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface);
2123 ULONG ref = InterlockedDecrement(&This->ref);
2125 if (!ref)
2127 HeapFree(GetProcessHeap(), 0, This);
2128 return 0;
2130 return ref;
2133 static HRESULT WINAPI IOleCommandTargetImpl_QueryStatus(
2134 IOleCommandTarget *iface, const GUID *group, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText)
2136 return E_NOTIMPL;
2139 static HRESULT WINAPI IOleCommandTargetImpl_Exec(
2140 IOleCommandTarget *iface,
2141 const GUID *CmdGroup,
2142 DWORD nCmdID,
2143 DWORD nCmdexecopt,
2144 VARIANT *pvaIn,
2145 VARIANT *pvaOut)
2147 add_call(&trace_got, 3, CmdGroup, (void*)(DWORD_PTR)nCmdID, (void*)(DWORD_PTR)nCmdexecopt, pvaIn, pvaOut);
2148 return S_OK;
2151 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl =
2153 IOleCommandTargetImpl_QueryInterface,
2154 IOleCommandTargetImpl_AddRef,
2155 IOleCommandTargetImpl_Release,
2156 IOleCommandTargetImpl_QueryStatus,
2157 IOleCommandTargetImpl_Exec
2160 typedef struct {
2161 IServiceProvider IServiceProvider_iface;
2162 LONG ref;
2163 } IServiceProviderImpl;
2165 static inline IServiceProviderImpl *impl_from_IServiceProvider(IServiceProvider *iface)
2167 return CONTAINING_RECORD(iface, IServiceProviderImpl, IServiceProvider_iface);
2170 typedef struct {
2171 IProfferService IProfferService_iface;
2172 LONG ref;
2173 } IProfferServiceImpl;
2175 static inline IProfferServiceImpl *impl_from_IProfferService(IProfferService *iface)
2177 return CONTAINING_RECORD(iface, IProfferServiceImpl, IProfferService_iface);
2181 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl;
2182 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl;
2184 static IServiceProvider* IServiceProviderImpl_Construct(void)
2186 IServiceProviderImpl *obj;
2188 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2189 obj->IServiceProvider_iface.lpVtbl = &IServiceProviderImpl_Vtbl;
2190 obj->ref = 1;
2192 return &obj->IServiceProvider_iface;
2195 static IProfferService* IProfferServiceImpl_Construct(void)
2197 IProfferServiceImpl *obj;
2199 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2200 obj->IProfferService_iface.lpVtbl = &IProfferServiceImpl_Vtbl;
2201 obj->ref = 1;
2203 return &obj->IProfferService_iface;
2206 static HRESULT WINAPI IServiceProviderImpl_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppvObj)
2208 IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
2210 if (IsEqualIID(riid, &IID_IUnknown) ||
2211 IsEqualIID(riid, &IID_IServiceProvider))
2213 *ppvObj = This;
2216 if(*ppvObj)
2218 IUnknown_AddRef(iface);
2219 /* native uses redefined IID_IServiceProvider symbol, so we can't compare pointers */
2220 if (IsEqualIID(riid, &IID_IServiceProvider))
2221 add_call(&trace_got, 1, iface, &IID_IServiceProvider, 0, 0, 0);
2222 return S_OK;
2225 return E_NOINTERFACE;
2228 static ULONG WINAPI IServiceProviderImpl_AddRef(IServiceProvider *iface)
2230 IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
2231 return InterlockedIncrement(&This->ref);
2234 static ULONG WINAPI IServiceProviderImpl_Release(IServiceProvider *iface)
2236 IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
2237 ULONG ref = InterlockedDecrement(&This->ref);
2239 if (!ref)
2241 HeapFree(GetProcessHeap(), 0, This);
2242 return 0;
2244 return ref;
2247 static HRESULT WINAPI IServiceProviderImpl_QueryService(
2248 IServiceProvider *iface, REFGUID service, REFIID riid, void **ppv)
2250 /* native uses redefined pointer for IID_IOleCommandTarget, not one from uuid.lib */
2251 if (IsEqualIID(riid, &IID_IOleCommandTarget))
2253 add_call(&trace_got, 2, iface, service, &IID_IOleCommandTarget, 0, 0);
2254 *ppv = IOleCommandTargetImpl_Construct();
2256 if (IsEqualIID(riid, &IID_IProfferService))
2258 if (IsEqualIID(service, &IID_IProfferService))
2259 add_call(&trace_got, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2260 *ppv = IProfferServiceImpl_Construct();
2262 return S_OK;
2265 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl =
2267 IServiceProviderImpl_QueryInterface,
2268 IServiceProviderImpl_AddRef,
2269 IServiceProviderImpl_Release,
2270 IServiceProviderImpl_QueryService
2273 static void test_IUnknown_QueryServiceExec(void)
2275 IServiceProvider *provider = IServiceProviderImpl_Construct();
2276 static const GUID dummy_serviceid = { 0xdeadbeef };
2277 static const GUID dummy_groupid = { 0xbeefbeef };
2278 call_trace_t trace_expected;
2279 HRESULT hr;
2281 /* on <=W2K platforms same ordinal used for another export with different
2282 prototype, so skipping using this indirect condition */
2283 if (is_win2k_and_lower)
2285 win_skip("IUnknown_QueryServiceExec is not available\n");
2286 return;
2289 /* null source pointer */
2290 hr = pIUnknown_QueryServiceExec(NULL, &dummy_serviceid, &dummy_groupid, 0, 0, 0, 0);
2291 ok(hr == E_FAIL, "got 0x%08x\n", hr);
2293 /* expected trace:
2294 IUnknown_QueryServiceExec( ptr1, serviceid, groupid, arg1, arg2, arg3, arg4);
2295 -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &prov );
2296 -> IServiceProvider_QueryService( prov, serviceid, &IID_IOleCommandTarget, &obj );
2297 -> IOleCommandTarget_Exec( obj, groupid, arg1, arg2, arg3, arg4 );
2299 init_call_trace(&trace_expected);
2301 add_call(&trace_expected, 1, provider, &IID_IServiceProvider, 0, 0, 0);
2302 add_call(&trace_expected, 2, provider, &dummy_serviceid, &IID_IOleCommandTarget, 0, 0);
2303 add_call(&trace_expected, 3, &dummy_groupid, (void*)0x1, (void*)0x2, (void*)0x3, (void*)0x4);
2305 init_call_trace(&trace_got);
2306 hr = pIUnknown_QueryServiceExec((IUnknown*)provider, &dummy_serviceid, &dummy_groupid, 0x1, 0x2, (void*)0x3, (void*)0x4);
2307 ok(hr == S_OK, "got 0x%08x\n", hr);
2309 ok_trace(&trace_expected, &trace_got);
2311 free_call_trace(&trace_expected);
2312 free_call_trace(&trace_got);
2314 IServiceProvider_Release(provider);
2318 static HRESULT WINAPI IProfferServiceImpl_QueryInterface(IProfferService *iface, REFIID riid, void **ppvObj)
2320 IProfferServiceImpl *This = impl_from_IProfferService(iface);
2322 if (IsEqualIID(riid, &IID_IUnknown) ||
2323 IsEqualIID(riid, &IID_IProfferService))
2325 *ppvObj = This;
2327 else if (IsEqualIID(riid, &IID_IServiceProvider))
2329 *ppvObj = IServiceProviderImpl_Construct();
2330 add_call(&trace_got, 1, iface, &IID_IServiceProvider, 0, 0, 0);
2331 return S_OK;
2334 if(*ppvObj)
2336 IUnknown_AddRef(iface);
2337 return S_OK;
2340 return E_NOINTERFACE;
2343 static ULONG WINAPI IProfferServiceImpl_AddRef(IProfferService *iface)
2345 IProfferServiceImpl *This = impl_from_IProfferService(iface);
2346 return InterlockedIncrement(&This->ref);
2349 static ULONG WINAPI IProfferServiceImpl_Release(IProfferService *iface)
2351 IProfferServiceImpl *This = impl_from_IProfferService(iface);
2352 ULONG ref = InterlockedDecrement(&This->ref);
2354 if (!ref)
2356 HeapFree(GetProcessHeap(), 0, This);
2357 return 0;
2359 return ref;
2362 static HRESULT WINAPI IProfferServiceImpl_ProfferService(IProfferService *iface,
2363 REFGUID service, IServiceProvider *pService, DWORD *pCookie)
2365 *pCookie = 0xdeadbeef;
2366 add_call(&trace_got, 3, service, pService, pCookie, 0, 0);
2367 return S_OK;
2370 static HRESULT WINAPI IProfferServiceImpl_RevokeService(IProfferService *iface, DWORD cookie)
2372 add_call(&trace_got, 4, (void*)(DWORD_PTR)cookie, 0, 0, 0, 0);
2373 return S_OK;
2376 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl =
2378 IProfferServiceImpl_QueryInterface,
2379 IProfferServiceImpl_AddRef,
2380 IProfferServiceImpl_Release,
2381 IProfferServiceImpl_ProfferService,
2382 IProfferServiceImpl_RevokeService
2385 static void test_IUnknown_ProfferService(void)
2387 IServiceProvider *provider = IServiceProviderImpl_Construct();
2388 IProfferService *proff = IProfferServiceImpl_Construct();
2389 static const GUID dummy_serviceid = { 0xdeadbeef };
2390 call_trace_t trace_expected;
2391 HRESULT hr;
2392 DWORD cookie;
2394 /* on <=W2K platforms same ordinal used for another export with different
2395 prototype, so skipping using this indirect condition */
2396 if (is_win2k_and_lower)
2398 win_skip("IUnknown_ProfferService is not available\n");
2399 return;
2402 /* null source pointer */
2403 hr = pIUnknown_ProfferService(NULL, &dummy_serviceid, 0, 0);
2404 ok(hr == E_FAIL, "got 0x%08x\n", hr);
2406 /* expected trace:
2407 IUnknown_ProfferService( ptr1, serviceid, arg1, arg2);
2408 -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &provider );
2409 -> IServiceProvider_QueryService( provider, &IID_IProfferService, &IID_IProfferService, &proffer );
2411 if (service pointer not null):
2412 -> IProfferService_ProfferService( proffer, serviceid, arg1, arg2 );
2413 else
2414 -> IProfferService_RevokeService( proffer, *arg2 );
2416 init_call_trace(&trace_expected);
2418 add_call(&trace_expected, 1, proff, &IID_IServiceProvider, 0, 0, 0);
2419 add_call(&trace_expected, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2420 add_call(&trace_expected, 3, &dummy_serviceid, provider, &cookie, 0, 0);
2422 init_call_trace(&trace_got);
2423 cookie = 0;
2424 hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, provider, &cookie);
2425 ok(hr == S_OK, "got 0x%08x\n", hr);
2426 ok(cookie == 0xdeadbeef, "got %x\n", cookie);
2428 ok_trace(&trace_expected, &trace_got);
2429 free_call_trace(&trace_got);
2430 free_call_trace(&trace_expected);
2432 /* same with ::Revoke path */
2433 init_call_trace(&trace_expected);
2435 add_call(&trace_expected, 1, proff, &IID_IServiceProvider, 0, 0, 0);
2436 add_call(&trace_expected, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2437 add_call(&trace_expected, 4, (void*)(DWORD_PTR)cookie, 0, 0, 0, 0);
2439 init_call_trace(&trace_got);
2440 ok(cookie != 0, "got %x\n", cookie);
2441 hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, 0, &cookie);
2442 ok(hr == S_OK, "got 0x%08x\n", hr);
2443 ok(cookie == 0, "got %x\n", cookie);
2444 ok_trace(&trace_expected, &trace_got);
2445 free_call_trace(&trace_got);
2446 free_call_trace(&trace_expected);
2448 IServiceProvider_Release(provider);
2449 IProfferService_Release(proff);
2452 static void test_SHCreateWorkerWindowA(void)
2454 WNDCLASSA cliA;
2455 char classA[20];
2456 HWND hwnd;
2457 LONG_PTR ret;
2458 BOOL res;
2460 if (is_win2k_and_lower)
2462 win_skip("SHCreateWorkerWindowA not available\n");
2463 return;
2466 hwnd = pSHCreateWorkerWindowA(0, NULL, 0, 0, 0, 0);
2467 ok(hwnd != 0, "expected window\n");
2469 GetClassName(hwnd, classA, 20);
2470 ok(lstrcmpA(classA, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA);
2472 ret = GetWindowLongPtrA(hwnd, 0);
2473 ok(ret == 0, "got %ld\n", ret);
2475 /* class info */
2476 memset(&cliA, 0, sizeof(cliA));
2477 res = GetClassInfoA(GetModuleHandle("shlwapi.dll"), "WorkerA", &cliA);
2478 ok(res, "failed to get class info\n");
2479 ok(cliA.style == 0, "got 0x%08x\n", cliA.style);
2480 ok(cliA.cbClsExtra == 0, "got %d\n", cliA.cbClsExtra);
2481 ok(cliA.cbWndExtra == sizeof(LONG_PTR), "got %d\n", cliA.cbWndExtra);
2482 ok(cliA.lpszMenuName == 0, "got %s\n", cliA.lpszMenuName);
2484 DestroyWindow(hwnd);
2486 /* set extra bytes */
2487 hwnd = pSHCreateWorkerWindowA(0, NULL, 0, 0, 0, 0xdeadbeef);
2488 ok(hwnd != 0, "expected window\n");
2490 GetClassName(hwnd, classA, 20);
2491 ok(lstrcmpA(classA, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA);
2493 ret = GetWindowLongPtrA(hwnd, 0);
2494 ok(ret == 0xdeadbeef, "got %ld\n", ret);
2496 /* test exstyle */
2497 ret = GetWindowLongA(hwnd, GWL_EXSTYLE);
2498 ok(ret == WS_EX_WINDOWEDGE ||
2499 ret == (WS_EX_WINDOWEDGE|WS_EX_LAYOUTRTL) /* systems with RTL locale */, "0x%08lx\n", ret);
2501 DestroyWindow(hwnd);
2503 hwnd = pSHCreateWorkerWindowA(0, NULL, WS_EX_TOOLWINDOW, 0, 0, 0);
2504 ret = GetWindowLongA(hwnd, GWL_EXSTYLE);
2505 ok(ret == (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW) ||
2506 ret == (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW|WS_EX_LAYOUTRTL) /* systems with RTL locale */, "0x%08lx\n", ret);
2507 DestroyWindow(hwnd);
2510 static HRESULT WINAPI SF_QueryInterface(IShellFolder *iface,
2511 REFIID riid, void **ppv)
2513 /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */
2514 ok(!IsEqualGUID(&IID_IShellFolder, riid),
2515 "Unexpected QI for IShellFolder\n");
2516 return E_NOINTERFACE;
2519 static ULONG WINAPI SF_AddRef(IShellFolder *iface)
2521 return 2;
2524 static ULONG WINAPI SF_Release(IShellFolder *iface)
2526 return 1;
2529 static HRESULT WINAPI SF_ParseDisplayName(IShellFolder *iface,
2530 HWND owner, LPBC reserved, LPOLESTR displayName, ULONG *eaten,
2531 LPITEMIDLIST *idl, ULONG *attr)
2533 ok(0, "Didn't expect ParseDisplayName\n");
2534 return E_NOTIMPL;
2537 static HRESULT WINAPI SF_EnumObjects(IShellFolder *iface,
2538 HWND owner, SHCONTF flags, IEnumIDList **enm)
2540 *enm = (IEnumIDList*)0xcafebabe;
2541 return S_OK;
2544 static HRESULT WINAPI SF_BindToObject(IShellFolder *iface,
2545 LPCITEMIDLIST idl, LPBC reserved, REFIID riid, void **obj)
2547 ok(0, "Didn't expect BindToObject\n");
2548 return E_NOTIMPL;
2551 static HRESULT WINAPI SF_BindToStorage(IShellFolder *iface,
2552 LPCITEMIDLIST idl, LPBC reserved, REFIID riid, void **obj)
2554 ok(0, "Didn't expect BindToStorage\n");
2555 return E_NOTIMPL;
2558 static HRESULT WINAPI SF_CompareIDs(IShellFolder *iface,
2559 LPARAM lparam, LPCITEMIDLIST idl1, LPCITEMIDLIST idl2)
2561 ok(0, "Didn't expect CompareIDs\n");
2562 return E_NOTIMPL;
2565 static HRESULT WINAPI SF_CreateViewObject(IShellFolder *iface,
2566 HWND owner, REFIID riid, void **out)
2568 ok(0, "Didn't expect CreateViewObject\n");
2569 return E_NOTIMPL;
2572 static HRESULT WINAPI SF_GetAttributesOf(IShellFolder *iface,
2573 UINT cidl, LPCITEMIDLIST *idl, SFGAOF *inOut)
2575 ok(0, "Didn't expect GetAttributesOf\n");
2576 return E_NOTIMPL;
2579 static HRESULT WINAPI SF_GetUIObjectOf(IShellFolder *iface,
2580 HWND owner, UINT cidl, LPCITEMIDLIST *idls, REFIID riid, UINT *inOut,
2581 void **out)
2583 ok(0, "Didn't expect GetUIObjectOf\n");
2584 return E_NOTIMPL;
2587 static HRESULT WINAPI SF_GetDisplayNameOf(IShellFolder *iface,
2588 LPCITEMIDLIST idl, SHGDNF flags, STRRET *name)
2590 ok(0, "Didn't expect GetDisplayNameOf\n");
2591 return E_NOTIMPL;
2594 static HRESULT WINAPI SF_SetNameOf(IShellFolder *iface,
2595 HWND hwnd, LPCITEMIDLIST idl, LPCOLESTR name, SHGDNF flags,
2596 LPITEMIDLIST *idlOut)
2598 ok(0, "Didn't expect SetNameOf\n");
2599 return E_NOTIMPL;
2602 static IShellFolderVtbl ShellFolderVtbl = {
2603 SF_QueryInterface,
2604 SF_AddRef,
2605 SF_Release,
2606 SF_ParseDisplayName,
2607 SF_EnumObjects,
2608 SF_BindToObject,
2609 SF_BindToStorage,
2610 SF_CompareIDs,
2611 SF_CreateViewObject,
2612 SF_GetAttributesOf,
2613 SF_GetUIObjectOf,
2614 SF_GetDisplayNameOf,
2615 SF_SetNameOf
2618 static IShellFolder ShellFolder = { &ShellFolderVtbl };
2620 static void test_SHIShellFolder_EnumObjects(void)
2622 IEnumIDList *enm;
2623 HRESULT hres;
2624 IShellFolder *folder;
2626 if(!pSHIShellFolder_EnumObjects || is_win2k_and_lower){
2627 win_skip("SHIShellFolder_EnumObjects not available\n");
2628 return;
2631 if(0){
2632 /* NULL object crashes on Windows */
2633 pSHIShellFolder_EnumObjects(NULL, NULL, 0, NULL);
2636 /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */
2637 enm = (IEnumIDList*)0xdeadbeef;
2638 hres = pSHIShellFolder_EnumObjects(&ShellFolder, NULL, 0, &enm);
2639 ok(hres == S_OK, "SHIShellFolder_EnumObjects failed: 0x%08x\n", hres);
2640 ok(enm == (IEnumIDList*)0xcafebabe, "Didn't get expected enumerator location, instead: %p\n", enm);
2642 /* SHIShellFolder_EnumObjects isn't strict about the IShellFolder object */
2643 hres = pSHGetDesktopFolder(&folder);
2644 ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
2646 enm = NULL;
2647 hres = pSHIShellFolder_EnumObjects(folder, NULL, 0, &enm);
2648 ok(hres == S_OK, "SHIShellFolder_EnumObjects failed: 0x%08x\n", hres);
2649 ok(enm != NULL, "Didn't get an enumerator\n");
2650 if(enm)
2651 IEnumIDList_Release(enm);
2653 IShellFolder_Release(folder);
2656 static void write_inifile(LPCWSTR filename)
2658 DWORD written;
2659 HANDLE file;
2661 static const char data[] =
2662 "[TestApp]\r\n"
2663 "AKey=1\r\n"
2664 "AnotherKey=asdf\r\n";
2666 file = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
2667 if(file == INVALID_HANDLE_VALUE)
2668 return;
2670 WriteFile(file, data, sizeof(data), &written, NULL);
2672 CloseHandle(file);
2675 #define verify_inifile(f, e) r_verify_inifile(__LINE__, f, e)
2676 static void r_verify_inifile(unsigned l, LPCWSTR filename, LPCSTR exp)
2678 HANDLE file;
2679 CHAR buf[1024];
2680 DWORD read;
2682 file = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
2683 if(file == INVALID_HANDLE_VALUE)
2684 return;
2686 ReadFile(file, buf, sizeof(buf) * sizeof(CHAR), &read, NULL);
2687 buf[read] = '\0';
2689 CloseHandle(file);
2691 ok_(__FILE__,l)(!strcmp(buf, exp), "Expected:\n%s\nGot:\n%s\n", exp,
2692 buf);
2695 static void test_SHGetIniString(void)
2697 DWORD ret;
2698 WCHAR out[64] = {0};
2700 static const WCHAR TestAppW[] = {'T','e','s','t','A','p','p',0};
2701 static const WCHAR TestIniW[] = {'C',':','\\','t','e','s','t','.','i','n','i',0};
2702 static const WCHAR AKeyW[] = {'A','K','e','y',0};
2703 static const WCHAR AnotherKeyW[] = {'A','n','o','t','h','e','r','K','e','y',0};
2704 static const WCHAR JunkKeyW[] = {'J','u','n','k','K','e','y',0};
2706 if(!pSHGetIniStringW || is_win2k_and_lower){
2707 win_skip("SHGetIniStringW is not available\n");
2708 return;
2711 write_inifile(TestIniW);
2713 if(0){
2714 /* these crash on Windows */
2715 pSHGetIniStringW(NULL, NULL, NULL, 0, NULL);
2716 pSHGetIniStringW(NULL, AKeyW, out, sizeof(out), TestIniW);
2717 pSHGetIniStringW(TestAppW, AKeyW, NULL, sizeof(out), TestIniW);
2720 ret = pSHGetIniStringW(TestAppW, AKeyW, out, 0, TestIniW);
2721 ok(ret == 0, "SHGetIniStringW should have given 0, instead: %d\n", ret);
2723 /* valid arguments */
2724 ret = pSHGetIniStringW(TestAppW, NULL, out, sizeof(out), TestIniW);
2725 ok(broken(ret == 0) || /* win 98 */
2726 ret == 4, "SHGetIniStringW should have given 4, instead: %d\n", ret);
2727 ok(!lstrcmpW(out, AKeyW), "Expected %s, got: %s\n",
2728 wine_dbgstr_w(AKeyW), wine_dbgstr_w(out));
2730 ret = pSHGetIniStringW(TestAppW, AKeyW, out, sizeof(out), TestIniW);
2731 ok(broken(ret == 0) || /* win 98 */
2732 ret == 1, "SHGetIniStringW should have given 1, instead: %d\n", ret);
2733 ok(broken(*out == 0) || /*win 98 */
2734 !strcmp_wa(out, "1"), "Expected L\"1\", got: %s\n", wine_dbgstr_w(out));
2736 ret = pSHGetIniStringW(TestAppW, AnotherKeyW, out, sizeof(out), TestIniW);
2737 ok(broken(ret == 0) || /* win 98 */
2738 ret == 4, "SHGetIniStringW should have given 4, instead: %d\n", ret);
2739 ok(broken(*out == 0) || /* win 98 */
2740 !strcmp_wa(out, "asdf"), "Expected L\"asdf\", got: %s\n", wine_dbgstr_w(out));
2742 ret = pSHGetIniStringW(TestAppW, JunkKeyW, out, sizeof(out), TestIniW);
2743 ok(ret == 0, "SHGetIniStringW should have given 0, instead: %d\n", ret);
2744 ok(*out == 0, "Expected L\"\", got: %s\n", wine_dbgstr_w(out));
2746 DeleteFileW(TestIniW);
2749 static void test_SHSetIniString(void)
2751 BOOL ret;
2753 static const WCHAR TestAppW[] = {'T','e','s','t','A','p','p',0};
2754 static const WCHAR AnotherAppW[] = {'A','n','o','t','h','e','r','A','p','p',0};
2755 static const WCHAR TestIniW[] = {'C',':','\\','t','e','s','t','.','i','n','i',0};
2756 static const WCHAR AKeyW[] = {'A','K','e','y',0};
2757 static const WCHAR NewKeyW[] = {'N','e','w','K','e','y',0};
2758 static const WCHAR AValueW[] = {'A','V','a','l','u','e',0};
2760 if(!pSHSetIniStringW || is_win2k_and_lower){
2761 win_skip("SHSetIniStringW is not available\n");
2762 return;
2765 write_inifile(TestIniW);
2767 ret = pSHSetIniStringW(TestAppW, AKeyW, AValueW, TestIniW);
2768 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2769 todo_wine /* wine sticks an extra \r\n at the end of the file */
2770 verify_inifile(TestIniW, "[TestApp]\r\nAKey=AValue\r\nAnotherKey=asdf\r\n");
2772 ret = pSHSetIniStringW(TestAppW, AKeyW, NULL, TestIniW);
2773 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2774 verify_inifile(TestIniW, "[TestApp]\r\nAnotherKey=asdf\r\n");
2776 ret = pSHSetIniStringW(AnotherAppW, NewKeyW, AValueW, TestIniW);
2777 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2778 verify_inifile(TestIniW, "[TestApp]\r\nAnotherKey=asdf\r\n[AnotherApp]\r\nNewKey=AValue\r\n");
2780 ret = pSHSetIniStringW(TestAppW, NULL, AValueW, TestIniW);
2781 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2782 verify_inifile(TestIniW, "[AnotherApp]\r\nNewKey=AValue\r\n");
2784 DeleteFileW(TestIniW);
2787 enum _shellkey_flags {
2788 SHKEY_Root_HKCU = 0x1,
2789 SHKEY_Root_HKLM = 0x2,
2790 SHKEY_Key_Explorer = 0x00,
2791 SHKEY_Key_Shell = 0x10,
2792 SHKEY_Key_ShellNoRoam = 0x20,
2793 SHKEY_Key_Classes = 0x30,
2794 SHKEY_Subkey_Default = 0x0000,
2795 SHKEY_Subkey_ResourceName = 0x1000,
2796 SHKEY_Subkey_Handlers = 0x2000,
2797 SHKEY_Subkey_Associations = 0x3000,
2798 SHKEY_Subkey_Volatile = 0x4000,
2799 SHKEY_Subkey_MUICache = 0x5000,
2800 SHKEY_Subkey_FileExts = 0x6000
2803 static void test_SHGetShellKey(void)
2805 static const WCHAR ShellFoldersW[] = { 'S','h','e','l','l',' ','F','o','l','d','e','r','s',0 };
2806 static const WCHAR WineTestW[] = { 'W','i','n','e','T','e','s','t',0 };
2808 void *pPathBuildRootW = GetProcAddress(hShlwapi, "PathBuildRootW");
2809 DWORD *alloc_data, data, size;
2810 HKEY hkey;
2811 HRESULT hres;
2813 if (!pSHGetShellKey)
2815 win_skip("SHGetShellKey(ordinal 491) isn't available\n");
2816 return;
2819 /* some win2k */
2820 if (pPathBuildRootW && pPathBuildRootW == pSHGetShellKey)
2822 win_skip("SHGetShellKey(ordinal 491) used for PathBuildRootW\n");
2823 return;
2826 if (is_win9x || is_win2k_and_lower)
2828 win_skip("Ordinal 491 used for another call, skipping SHGetShellKey tests\n");
2829 return;
2832 /* Vista+ limits SHKEY enumeration values */
2833 SetLastError(0xdeadbeef);
2834 hkey = pSHGetShellKey(SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2835 if (hkey)
2837 /* Tests not working on Vista+ */
2838 RegCloseKey(hkey);
2840 hkey = pSHGetShellKey(SHKEY_Root_HKLM|SHKEY_Key_Classes, NULL, FALSE);
2841 ok(hkey != NULL, "hkey = NULL\n");
2842 RegCloseKey(hkey);
2845 hkey = pSHGetShellKey(SHKEY_Root_HKCU|SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2846 ok(hkey != NULL, "hkey = NULL\n");
2847 RegCloseKey(hkey);
2849 hkey = pSHGetShellKey(SHKEY_Root_HKLM|SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2850 ok(hkey != NULL, "hkey = NULL\n");
2851 RegCloseKey(hkey);
2853 hkey = pSHGetShellKey(SHKEY_Root_HKLM, WineTestW, FALSE);
2854 ok(hkey == NULL, "hkey != NULL\n");
2856 hkey = pSHGetShellKey(SHKEY_Root_HKLM, NULL, FALSE);
2857 ok(hkey != NULL, "Can't open key\n");
2858 ok(SUCCEEDED(RegDeleteKeyW(hkey, WineTestW)), "Can't delte key\n");
2859 RegCloseKey(hkey);
2861 hkey = pSHGetShellKey(SHKEY_Root_HKLM, WineTestW, TRUE);
2862 if (!hkey && GetLastError() == ERROR_ACCESS_DENIED)
2864 skip("Not authorized to create keys\n");
2865 return;
2867 ok(hkey != NULL, "Can't create key\n");
2868 RegCloseKey(hkey);
2870 if (!pSKGetValueW || !pSKSetValueW || !pSKDeleteValueW || !pSKAllocValueW)
2872 win_skip("SKGetValueW, SKSetValueW, SKDeleteValueW or SKAllocValueW not available\n");
2873 return;
2876 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
2877 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres);
2879 data = 1234;
2880 hres = pSKSetValueW(SHKEY_Root_HKLM, WineTestW, NULL, REG_DWORD, &data, sizeof(DWORD));
2881 ok(hres == S_OK, "hres = %x\n", hres);
2883 size = 1;
2884 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, NULL, &size);
2885 ok(hres == S_OK, "hres = %x\n", hres);
2886 ok(size == sizeof(DWORD), "size = %d\n", size);
2888 data = 0xdeadbeef;
2889 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
2890 ok(hres == S_OK, "hres = %x\n", hres);
2891 ok(size == sizeof(DWORD), "size = %d\n", size);
2892 ok(data == 1234, "data = %d\n", data);
2894 hres = pSKAllocValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, (void**)&alloc_data, &size);
2895 ok(hres == S_OK, "hres= %x\n", hres);
2896 ok(size == sizeof(DWORD), "size = %d\n", size);
2897 if (SUCCEEDED(hres))
2899 ok(*alloc_data == 1234, "*alloc_data = %d\n", *alloc_data);
2900 LocalFree(alloc_data);
2903 hres = pSKDeleteValueW(SHKEY_Root_HKLM, WineTestW, NULL);
2904 ok(hres == S_OK, "hres = %x\n", hres);
2906 hres = pSKDeleteValueW(SHKEY_Root_HKLM, WineTestW, NULL);
2907 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres);
2909 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
2910 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres);
2912 hkey = pSHGetShellKey(SHKEY_Root_HKLM, NULL, FALSE);
2913 ok(hkey != NULL, "Can't create key\n");
2914 ok(SUCCEEDED(RegDeleteKeyW(hkey, WineTestW)), "Can't delte key\n");
2915 RegCloseKey(hkey);
2918 static void init_pointers(void)
2920 #define MAKEFUNC(f, ord) (p##f = (void*)GetProcAddress(hShlwapi, (LPSTR)(ord)))
2921 MAKEFUNC(SHAllocShared, 7);
2922 MAKEFUNC(SHLockShared, 8);
2923 MAKEFUNC(SHUnlockShared, 9);
2924 MAKEFUNC(SHFreeShared, 10);
2925 MAKEFUNC(GetAcceptLanguagesA, 14);
2926 MAKEFUNC(SHSetWindowBits, 165);
2927 MAKEFUNC(ConnectToConnectionPoint, 168);
2928 MAKEFUNC(SHSearchMapInt, 198);
2929 MAKEFUNC(SHCreateWorkerWindowA, 257);
2930 MAKEFUNC(GUIDFromStringA, 269);
2931 MAKEFUNC(SHPackDispParams, 282);
2932 MAKEFUNC(IConnectionPoint_InvokeWithCancel, 283);
2933 MAKEFUNC(IConnectionPoint_SimpleInvoke, 284);
2934 MAKEFUNC(SHGetIniStringW, 294);
2935 MAKEFUNC(SHSetIniStringW, 295);
2936 MAKEFUNC(SHFormatDateTimeA, 353);
2937 MAKEFUNC(SHFormatDateTimeW, 354);
2938 MAKEFUNC(SHIShellFolder_EnumObjects, 404);
2939 MAKEFUNC(SHGetObjectCompatFlags, 476);
2940 MAKEFUNC(IUnknown_QueryServiceExec, 484);
2941 MAKEFUNC(SHGetShellKey, 491);
2942 MAKEFUNC(SHPropertyBag_ReadLONG, 496);
2943 MAKEFUNC(IUnknown_ProfferService, 514);
2944 MAKEFUNC(SKGetValueW, 516);
2945 MAKEFUNC(SKSetValueW, 517);
2946 MAKEFUNC(SKDeleteValueW, 518);
2947 MAKEFUNC(SKAllocValueW, 519);
2948 #undef MAKEFUNC
2951 START_TEST(ordinal)
2953 hShlwapi = GetModuleHandleA("shlwapi.dll");
2954 is_win2k_and_lower = GetProcAddress(hShlwapi, "StrChrNW") == 0;
2955 is_win9x = GetProcAddress(hShlwapi, (LPSTR)99) == 0; /* StrCpyNXA */
2957 /* SHCreateStreamOnFileEx was introduced in shlwapi v6.0 */
2958 if(!GetProcAddress(hShlwapi, "SHCreateStreamOnFileEx")){
2959 win_skip("Too old shlwapi version\n");
2960 return;
2963 init_pointers();
2965 hmlang = LoadLibraryA("mlang.dll");
2966 pLcidToRfc1766A = (void *)GetProcAddress(hmlang, "LcidToRfc1766A");
2968 hshell32 = LoadLibraryA("shell32.dll");
2969 pSHGetDesktopFolder = (void *)GetProcAddress(hshell32, "SHGetDesktopFolder");
2971 test_GetAcceptLanguagesA();
2972 test_SHSearchMapInt();
2973 test_alloc_shared();
2974 test_fdsa();
2975 test_GetShellSecurityDescriptor();
2976 test_SHPackDispParams();
2977 test_IConnectionPoint();
2978 test_SHPropertyBag_ReadLONG();
2979 test_SHSetWindowBits();
2980 test_SHFormatDateTimeA();
2981 test_SHFormatDateTimeW();
2982 test_SHGetObjectCompatFlags();
2983 test_IUnknown_QueryServiceExec();
2984 test_IUnknown_ProfferService();
2985 test_SHCreateWorkerWindowA();
2986 test_SHIShellFolder_EnumObjects();
2987 test_SHGetIniString();
2988 test_SHSetIniString();
2989 test_SHGetShellKey();
2991 FreeLibrary(hshell32);
2992 FreeLibrary(hmlang);