shlwapi/tests: Fix SHFormatDateTimeW tests for right-to-left locales.
[wine/multimedia.git] / dlls / shlwapi / tests / ordinal.c
blobcb90d3123524e57f9db1fd4cb25517723e2dbe72
1 /* Unit test suite for SHLWAPI ordinal functions
3 * Copyright 2004 Jon Griffiths
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include <stdio.h>
22 #define COBJMACROS
23 #define CONST_VTABLE
24 #include "wine/test.h"
25 #include "winbase.h"
26 #include "winerror.h"
27 #include "winuser.h"
28 #include "ole2.h"
29 #include "oaidl.h"
30 #include "ocidl.h"
31 #include "mlang.h"
32 #include "shlwapi.h"
33 #include "docobj.h"
34 #include "shobjidl.h"
35 #include "shlobj.h"
37 /* Function ptrs for ordinal calls */
38 static HMODULE hShlwapi;
39 static BOOL is_win2k_and_lower;
40 static BOOL is_win9x;
42 static int (WINAPI *pSHSearchMapInt)(const int*,const int*,int,int);
43 static HRESULT (WINAPI *pGetAcceptLanguagesA)(LPSTR,LPDWORD);
45 static HANDLE (WINAPI *pSHAllocShared)(LPCVOID,DWORD,DWORD);
46 static LPVOID (WINAPI *pSHLockShared)(HANDLE,DWORD);
47 static BOOL (WINAPI *pSHUnlockShared)(LPVOID);
48 static BOOL (WINAPI *pSHFreeShared)(HANDLE,DWORD);
49 static HRESULT(WINAPIV *pSHPackDispParams)(DISPPARAMS*,VARIANTARG*,UINT,...);
50 static HRESULT(WINAPI *pIConnectionPoint_SimpleInvoke)(IConnectionPoint*,DISPID,DISPPARAMS*);
51 static HRESULT(WINAPI *pIConnectionPoint_InvokeWithCancel)(IConnectionPoint*,DISPID,DISPPARAMS*,DWORD,DWORD);
52 static HRESULT(WINAPI *pConnectToConnectionPoint)(IUnknown*,REFIID,BOOL,IUnknown*, LPDWORD,IConnectionPoint **);
53 static HRESULT(WINAPI *pSHPropertyBag_ReadLONG)(IPropertyBag *,LPCWSTR,LPLONG);
54 static LONG (WINAPI *pSHSetWindowBits)(HWND, INT, UINT, UINT);
55 static INT (WINAPI *pSHFormatDateTimeA)(const FILETIME UNALIGNED*, DWORD*, LPSTR, UINT);
56 static INT (WINAPI *pSHFormatDateTimeW)(const FILETIME UNALIGNED*, DWORD*, LPWSTR, UINT);
57 static DWORD (WINAPI *pSHGetObjectCompatFlags)(IUnknown*, const CLSID*);
58 static BOOL (WINAPI *pGUIDFromStringA)(LPSTR, CLSID *);
59 static HRESULT (WINAPI *pIUnknown_QueryServiceExec)(IUnknown*, REFIID, const GUID*, DWORD, DWORD, VARIANT*, VARIANT*);
60 static HRESULT (WINAPI *pIUnknown_ProfferService)(IUnknown*, REFGUID, IServiceProvider*, DWORD*);
61 static HWND (WINAPI *pSHCreateWorkerWindowA)(LONG, HWND, DWORD, DWORD, HMENU, LONG_PTR);
62 static HRESULT (WINAPI *pSHIShellFolder_EnumObjects)(LPSHELLFOLDER, HWND, SHCONTF, IEnumIDList**);
63 static DWORD (WINAPI *pSHGetIniStringW)(LPCWSTR, LPCWSTR, LPWSTR, DWORD, LPCWSTR);
64 static BOOL (WINAPI *pSHSetIniStringW)(LPCWSTR, LPCWSTR, LPCWSTR, LPCWSTR);
65 static HKEY (WINAPI *pSHGetShellKey)(DWORD, LPCWSTR, BOOL);
66 static HRESULT (WINAPI *pSKGetValueW)(DWORD, LPCWSTR, LPCWSTR, DWORD*, void*, DWORD*);
67 static HRESULT (WINAPI *pSKSetValueW)(DWORD, LPCWSTR, LPCWSTR, DWORD, void*, DWORD);
68 static HRESULT (WINAPI *pSKDeleteValueW)(DWORD, LPCWSTR, LPCWSTR);
69 static HRESULT (WINAPI *pSKAllocValueW)(DWORD, LPCWSTR, LPCWSTR, DWORD*, void**, DWORD*);
70 static HWND (WINAPI *pSHSetParentHwnd)(HWND, HWND);
72 static HMODULE hmlang;
73 static HRESULT (WINAPI *pLcidToRfc1766A)(LCID, LPSTR, INT);
75 static HMODULE hshell32;
76 static HRESULT (WINAPI *pSHGetDesktopFolder)(IShellFolder**);
78 static const CHAR ie_international[] = {
79 'S','o','f','t','w','a','r','e','\\',
80 'M','i','c','r','o','s','o','f','t','\\',
81 'I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r','\\',
82 'I','n','t','e','r','n','a','t','i','o','n','a','l',0};
83 static const CHAR acceptlanguage[] = {
84 'A','c','c','e','p','t','L','a','n','g','u','a','g','e',0};
86 static int strcmp_wa(LPCWSTR strw, const char *stra)
88 CHAR buf[512];
89 WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL);
90 return lstrcmpA(stra, buf);
93 typedef struct {
94 int id;
95 const void *args[5];
96 } call_entry_t;
98 typedef struct {
99 call_entry_t *calls;
100 int count;
101 int alloc;
102 } call_trace_t;
104 static void init_call_trace(call_trace_t *ctrace)
106 ctrace->alloc = 10;
107 ctrace->count = 0;
108 ctrace->calls = HeapAlloc(GetProcessHeap(), 0, sizeof(call_entry_t) * ctrace->alloc);
111 static void free_call_trace(const call_trace_t *ctrace)
113 HeapFree(GetProcessHeap(), 0, ctrace->calls);
116 static void add_call(call_trace_t *ctrace, int id, const void *arg0,
117 const void *arg1, const void *arg2, const void *arg3, const void *arg4)
119 call_entry_t call;
121 call.id = id;
122 call.args[0] = arg0;
123 call.args[1] = arg1;
124 call.args[2] = arg2;
125 call.args[3] = arg3;
126 call.args[4] = arg4;
128 if (ctrace->count == ctrace->alloc)
130 ctrace->alloc *= 2;
131 ctrace->calls = HeapReAlloc(GetProcessHeap(),0, ctrace->calls, ctrace->alloc*sizeof(call_entry_t));
134 ctrace->calls[ctrace->count++] = call;
137 static void ok_trace_(call_trace_t *texpected, call_trace_t *tgot, int line)
139 if (texpected->count == tgot->count)
141 INT i;
142 /* compare */
143 for (i = 0; i < texpected->count; i++)
145 call_entry_t *expected = &texpected->calls[i];
146 call_entry_t *got = &tgot->calls[i];
147 INT j;
149 ok_(__FILE__, line)(expected->id == got->id, "got different ids %d: %d, %d\n", i+1, expected->id, got->id);
151 for (j = 0; j < 5; j++)
153 ok_(__FILE__, line)(expected->args[j] == got->args[j], "got different args[%d] for %d: %p, %p\n", j, i+1,
154 expected->args[j], got->args[j]);
158 else
159 ok_(__FILE__, line)(0, "traces length mismatch\n");
162 #define ok_trace(a, b) ok_trace_(a, b, __LINE__)
164 /* trace of actually made calls */
165 static call_trace_t trace_got;
167 static void test_GetAcceptLanguagesA(void)
169 static LPCSTR table[] = {"de,en-gb;q=0.7,en;q=0.3",
170 "de,en;q=0.3,en-gb;q=0.7", /* sorting is ignored */
171 "winetest", /* content is ignored */
172 "de-de,de;q=0.5",
173 "de",
174 NULL};
176 DWORD exactsize;
177 char original[512];
178 char language[32];
179 char buffer[64];
180 HKEY hroot = NULL;
181 LONG res_query = ERROR_SUCCESS;
182 LONG lres;
183 HRESULT hr;
184 DWORD maxlen = sizeof(buffer) - 2;
185 DWORD len;
186 LCID lcid;
187 LPCSTR entry;
188 INT i = 0;
190 if (!pGetAcceptLanguagesA) {
191 win_skip("GetAcceptLanguagesA is not available\n");
192 return;
195 lcid = GetUserDefaultLCID();
197 /* Get the original Value */
198 lres = RegOpenKeyA(HKEY_CURRENT_USER, ie_international, &hroot);
199 if (lres) {
200 skip("RegOpenKey(%s) failed: %d\n", ie_international, lres);
201 return;
203 len = sizeof(original);
204 original[0] = 0;
205 res_query = RegQueryValueExA(hroot, acceptlanguage, 0, NULL, (PBYTE)original, &len);
207 RegDeleteValueA(hroot, acceptlanguage);
209 /* Some windows versions use "lang-COUNTRY" as default */
210 memset(language, 0, sizeof(language));
211 len = GetLocaleInfoA(lcid, LOCALE_SISO639LANGNAME, language, sizeof(language));
213 if (len) {
214 lstrcatA(language, "-");
215 memset(buffer, 0, sizeof(buffer));
216 len = GetLocaleInfoA(lcid, LOCALE_SISO3166CTRYNAME, buffer, sizeof(buffer) - len - 1);
217 lstrcatA(language, buffer);
219 else
221 /* LOCALE_SNAME has additional parts in some languages. Try only as last chance */
222 memset(language, 0, sizeof(language));
223 len = GetLocaleInfoA(lcid, LOCALE_SNAME, language, sizeof(language));
226 /* get the default value */
227 len = maxlen;
228 memset(buffer, '#', maxlen);
229 buffer[maxlen] = 0;
230 hr = pGetAcceptLanguagesA( buffer, &len);
232 if (hr != S_OK) {
233 win_skip("GetAcceptLanguagesA failed with 0x%x\n", hr);
234 goto restore_original;
237 if (lstrcmpA(buffer, language)) {
238 /* some windows versions use "lang" or "lang-country" as default */
239 language[0] = 0;
240 if (pLcidToRfc1766A) {
241 hr = pLcidToRfc1766A(lcid, language, sizeof(language));
242 ok(hr == S_OK, "LcidToRfc1766A returned 0x%x and %s\n", hr, language);
246 ok(!lstrcmpA(buffer, language),
247 "have '%s' (searching for '%s')\n", language, buffer);
249 if (lstrcmpA(buffer, language)) {
250 win_skip("no more ideas, how to build the default language '%s'\n", buffer);
251 goto restore_original;
254 trace("detected default: %s\n", language);
255 while ((entry = table[i])) {
257 exactsize = lstrlenA(entry);
259 lres = RegSetValueExA(hroot, acceptlanguage, 0, REG_SZ, (const BYTE *) entry, exactsize + 1);
260 ok(!lres, "got %d for RegSetValueExA: %s\n", lres, entry);
262 /* len includes space for the terminating 0 before vista/w2k8 */
263 len = exactsize + 2;
264 memset(buffer, '#', maxlen);
265 buffer[maxlen] = 0;
266 hr = pGetAcceptLanguagesA( buffer, &len);
267 ok(((hr == E_INVALIDARG) && (len == 0)) ||
268 (SUCCEEDED(hr) &&
269 ((len == exactsize) || (len == exactsize+1)) &&
270 !lstrcmpA(buffer, entry)),
271 "+2_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
273 len = exactsize + 1;
274 memset(buffer, '#', maxlen);
275 buffer[maxlen] = 0;
276 hr = pGetAcceptLanguagesA( buffer, &len);
277 ok(((hr == E_INVALIDARG) && (len == 0)) ||
278 (SUCCEEDED(hr) &&
279 ((len == exactsize) || (len == exactsize+1)) &&
280 !lstrcmpA(buffer, entry)),
281 "+1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
283 len = exactsize;
284 memset(buffer, '#', maxlen);
285 buffer[maxlen] = 0;
286 hr = pGetAcceptLanguagesA( buffer, &len);
288 /* There is no space for the string in the registry.
289 When the buffer is large enough, the default language is returned
291 When the buffer is too small for that fallback, win7_32 and w2k8_64
292 fail with HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), win8 fails
293 with HRESULT_FROM_WIN32(ERROR_MORE_DATA), other versions succeed and
294 return a partial result while older os succeed and overflow the buffer */
296 ok(((hr == E_INVALIDARG) && (len == 0)) ||
297 (((hr == S_OK) && !lstrcmpA(buffer, language) && (len == lstrlenA(language))) ||
298 ((hr == S_OK) && !memcmp(buffer, language, len)) ||
299 ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len) ||
300 ((hr == __HRESULT_FROM_WIN32(ERROR_MORE_DATA)) && len == exactsize)),
301 "==_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
303 if (exactsize > 1) {
304 len = exactsize - 1;
305 memset(buffer, '#', maxlen);
306 buffer[maxlen] = 0;
307 hr = pGetAcceptLanguagesA( buffer, &len);
308 ok(((hr == E_INVALIDARG) && (len == 0)) ||
309 (((hr == S_OK) && !lstrcmpA(buffer, language) && (len == lstrlenA(language))) ||
310 ((hr == S_OK) && !memcmp(buffer, language, len)) ||
311 ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len) ||
312 ((hr == __HRESULT_FROM_WIN32(ERROR_MORE_DATA)) && len == exactsize - 1)),
313 "-1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
316 len = 1;
317 memset(buffer, '#', maxlen);
318 buffer[maxlen] = 0;
319 hr = pGetAcceptLanguagesA( buffer, &len);
320 ok(((hr == E_INVALIDARG) && (len == 0)) ||
321 (((hr == S_OK) && !lstrcmpA(buffer, language) && (len == lstrlenA(language))) ||
322 ((hr == S_OK) && !memcmp(buffer, language, len)) ||
323 ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len) ||
324 ((hr == __HRESULT_FROM_WIN32(ERROR_MORE_DATA)) && len == 1)),
325 "=1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
327 len = maxlen;
328 hr = pGetAcceptLanguagesA( NULL, &len);
330 /* w2k3 and below: E_FAIL and untouched len,
331 since w2k8: S_OK and needed size (excluding 0), win8 S_OK and size including 0. */
332 ok( ((hr == S_OK) && ((len == exactsize) || (len == exactsize + 1))) ||
333 ((hr == E_FAIL) && (len == maxlen)),
334 "NULL,max #%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
336 i++;
339 /* without a value in the registry, a default language is returned */
340 RegDeleteValueA(hroot, acceptlanguage);
342 len = maxlen;
343 memset(buffer, '#', maxlen);
344 buffer[maxlen] = 0;
345 hr = pGetAcceptLanguagesA( buffer, &len);
346 ok( ((hr == S_OK) && (len == lstrlenA(language))),
347 "max: got 0x%x with %d and %s (expected S_OK with %d and '%s'\n",
348 hr, len, buffer, lstrlenA(language), language);
350 len = 2;
351 memset(buffer, '#', maxlen);
352 buffer[maxlen] = 0;
353 hr = pGetAcceptLanguagesA( buffer, &len);
354 ok( (((hr == S_OK) || (hr == E_INVALIDARG)) && !memcmp(buffer, language, len)) ||
355 ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len) ||
356 ((hr == __HRESULT_FROM_WIN32(ERROR_CANNOT_COPY)) && !len),
357 "=2: got 0x%x with %d and %s\n", hr, len, buffer);
359 len = 1;
360 memset(buffer, '#', maxlen);
361 buffer[maxlen] = 0;
362 hr = pGetAcceptLanguagesA( buffer, &len);
363 /* When the buffer is too small, win7_32 and w2k8_64 and above fail with
364 HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), win8 ERROR_CANNOT_COPY,
365 other versions succeed and return a partial 0 terminated result while other versions
366 fail with E_INVALIDARG and return a partial unterminated result */
367 ok( (((hr == S_OK) || (hr == E_INVALIDARG)) && !memcmp(buffer, language, len)) ||
368 ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len) ||
369 ((hr == __HRESULT_FROM_WIN32(ERROR_CANNOT_COPY)) && !len),
370 "=1: got 0x%x with %d and %s\n", hr, len, buffer);
372 len = 0;
373 memset(buffer, '#', maxlen);
374 buffer[maxlen] = 0;
375 hr = pGetAcceptLanguagesA( buffer, &len);
376 /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG, win8 ERROR_CANNOT_COPY */
377 ok((hr == E_FAIL) || (hr == E_INVALIDARG) || (hr == __HRESULT_FROM_WIN32(ERROR_CANNOT_COPY)),
378 "got 0x%x\n", hr);
380 memset(buffer, '#', maxlen);
381 buffer[maxlen] = 0;
382 hr = pGetAcceptLanguagesA( buffer, 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);
388 hr = pGetAcceptLanguagesA( NULL, NULL);
389 /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG */
390 ok((hr == E_FAIL) || (hr == E_INVALIDARG),
391 "got 0x%x (expected E_FAIL or E_INVALIDARG)\n", hr);
393 restore_original:
394 if (!res_query) {
395 len = lstrlenA(original);
396 lres = RegSetValueExA(hroot, acceptlanguage, 0, REG_SZ, (const BYTE *) original, len ? len + 1: 0);
397 ok(!lres, "RegSetValueEx(%s) failed: %d\n", original, lres);
399 else
401 RegDeleteValueA(hroot, acceptlanguage);
403 RegCloseKey(hroot);
406 static void test_SHSearchMapInt(void)
408 int keys[8], values[8];
409 int i = 0;
411 if (!pSHSearchMapInt)
412 return;
414 memset(keys, 0, sizeof(keys));
415 memset(values, 0, sizeof(values));
416 keys[0] = 99; values[0] = 101;
418 /* NULL key/value lists crash native, so skip testing them */
420 /* 1 element */
421 i = pSHSearchMapInt(keys, values, 1, keys[0]);
422 ok(i == values[0], "Len 1, expected %d, got %d\n", values[0], i);
424 /* Key doesn't exist */
425 i = pSHSearchMapInt(keys, values, 1, 100);
426 ok(i == -1, "Len 1 - bad key, expected -1, got %d\n", i);
428 /* Len = 0 => not found */
429 i = pSHSearchMapInt(keys, values, 0, keys[0]);
430 ok(i == -1, "Len 1 - passed len 0, expected -1, got %d\n", i);
432 /* 2 elements, len = 1 */
433 keys[1] = 98; values[1] = 102;
434 i = pSHSearchMapInt(keys, values, 1, keys[1]);
435 ok(i == -1, "Len 1 - array len 2, expected -1, got %d\n", i);
437 /* 2 elements, len = 2 */
438 i = pSHSearchMapInt(keys, values, 2, keys[1]);
439 ok(i == values[1], "Len 2, expected %d, got %d\n", values[1], i);
441 /* Searches forward */
442 keys[2] = 99; values[2] = 103;
443 i = pSHSearchMapInt(keys, values, 3, keys[0]);
444 ok(i == values[0], "Len 3, expected %d, got %d\n", values[0], i);
447 static void test_alloc_shared(void)
449 DWORD procid;
450 HANDLE hmem;
451 int val;
452 int* p;
453 BOOL ret;
455 procid=GetCurrentProcessId();
456 hmem=pSHAllocShared(NULL,10,procid);
457 ok(hmem!=NULL,"SHAllocShared(NULL...) failed: %u\n", GetLastError());
458 ret = pSHFreeShared(hmem, procid);
459 ok( ret, "SHFreeShared failed: %u\n", GetLastError());
461 val=0x12345678;
462 hmem=pSHAllocShared(&val,4,procid);
463 ok(hmem!=NULL,"SHAllocShared(NULL...) failed: %u\n", GetLastError());
465 p=pSHLockShared(hmem,procid);
466 ok(p!=NULL,"SHLockShared failed: %u\n", GetLastError());
467 if (p!=NULL)
468 ok(*p==val,"Wrong value in shared memory: %d instead of %d\n",*p,val);
469 ret = pSHUnlockShared(p);
470 ok( ret, "SHUnlockShared failed: %u\n", GetLastError());
472 ret = pSHFreeShared(hmem, procid);
473 ok( ret, "SHFreeShared failed: %u\n", GetLastError());
476 static void test_fdsa(void)
478 typedef struct
480 DWORD num_items; /* Number of elements inserted */
481 void *mem; /* Ptr to array */
482 DWORD blocks_alloced; /* Number of elements allocated */
483 BYTE inc; /* Number of elements to grow by when we need to expand */
484 BYTE block_size; /* Size in bytes of an element */
485 BYTE flags; /* Flags */
486 } FDSA_info;
488 BOOL (WINAPI *pFDSA_Initialize)(DWORD block_size, DWORD inc, FDSA_info *info, void *mem,
489 DWORD init_blocks);
490 BOOL (WINAPI *pFDSA_Destroy)(FDSA_info *info);
491 DWORD (WINAPI *pFDSA_InsertItem)(FDSA_info *info, DWORD where, const void *block);
492 BOOL (WINAPI *pFDSA_DeleteItem)(FDSA_info *info, DWORD where);
494 FDSA_info info;
495 int block_size = 10, init_blocks = 4, inc = 2;
496 DWORD ret;
497 char *mem;
499 pFDSA_Initialize = (void *)GetProcAddress(hShlwapi, (LPSTR)208);
500 pFDSA_Destroy = (void *)GetProcAddress(hShlwapi, (LPSTR)209);
501 pFDSA_InsertItem = (void *)GetProcAddress(hShlwapi, (LPSTR)210);
502 pFDSA_DeleteItem = (void *)GetProcAddress(hShlwapi, (LPSTR)211);
504 mem = HeapAlloc(GetProcessHeap(), 0, block_size * init_blocks);
505 memset(&info, 0, sizeof(info));
507 ok(pFDSA_Initialize(block_size, inc, &info, mem, init_blocks), "FDSA_Initialize rets FALSE\n");
508 ok(info.num_items == 0, "num_items = %d\n", info.num_items);
509 ok(info.mem == mem, "mem = %p\n", info.mem);
510 ok(info.blocks_alloced == init_blocks, "blocks_alloced = %d\n", info.blocks_alloced);
511 ok(info.inc == inc, "inc = %d\n", info.inc);
512 ok(info.block_size == block_size, "block_size = %d\n", info.block_size);
513 ok(info.flags == 0, "flags = %d\n", info.flags);
515 ret = pFDSA_InsertItem(&info, 1234, "1234567890");
516 ok(ret == 0, "ret = %d\n", ret);
517 ok(info.num_items == 1, "num_items = %d\n", info.num_items);
518 ok(info.mem == mem, "mem = %p\n", info.mem);
519 ok(info.blocks_alloced == init_blocks, "blocks_alloced = %d\n", info.blocks_alloced);
520 ok(info.inc == inc, "inc = %d\n", info.inc);
521 ok(info.block_size == block_size, "block_size = %d\n", info.block_size);
522 ok(info.flags == 0, "flags = %d\n", info.flags);
524 ret = pFDSA_InsertItem(&info, 1234, "abcdefghij");
525 ok(ret == 1, "ret = %d\n", ret);
527 ret = pFDSA_InsertItem(&info, 1, "klmnopqrst");
528 ok(ret == 1, "ret = %d\n", ret);
530 ret = pFDSA_InsertItem(&info, 0, "uvwxyzABCD");
531 ok(ret == 0, "ret = %d\n", ret);
532 ok(info.mem == mem, "mem = %p\n", info.mem);
533 ok(info.flags == 0, "flags = %d\n", info.flags);
535 /* This next InsertItem will cause shlwapi to allocate its own mem buffer */
536 ret = pFDSA_InsertItem(&info, 0, "EFGHIJKLMN");
537 ok(ret == 0, "ret = %d\n", ret);
538 ok(info.mem != mem, "mem = %p\n", info.mem);
539 ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %d\n", info.blocks_alloced);
540 ok(info.flags == 0x1, "flags = %d\n", info.flags);
542 ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCD1234567890klmnopqrstabcdefghij", 50), "mem %s\n", (char*)info.mem);
544 ok(pFDSA_DeleteItem(&info, 2), "rets FALSE\n");
545 ok(info.mem != mem, "mem = %p\n", info.mem);
546 ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %d\n", info.blocks_alloced);
547 ok(info.flags == 0x1, "flags = %d\n", info.flags);
549 ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCDklmnopqrstabcdefghij", 40), "mem %s\n", (char*)info.mem);
551 ok(pFDSA_DeleteItem(&info, 3), "rets FALSE\n");
552 ok(info.mem != mem, "mem = %p\n", info.mem);
553 ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %d\n", info.blocks_alloced);
554 ok(info.flags == 0x1, "flags = %d\n", info.flags);
556 ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCDklmnopqrst", 30), "mem %s\n", (char*)info.mem);
558 ok(!pFDSA_DeleteItem(&info, 4), "does not ret FALSE\n");
560 /* As shlwapi has allocated memory internally, Destroy will ret FALSE */
561 ok(!pFDSA_Destroy(&info), "FDSA_Destroy does not ret FALSE\n");
564 /* When Initialize is called with inc = 0, set it to 1 */
565 ok(pFDSA_Initialize(block_size, 0, &info, mem, init_blocks), "FDSA_Initialize rets FALSE\n");
566 ok(info.inc == 1, "inc = %d\n", info.inc);
568 /* This time, because shlwapi hasn't had to allocate memory
569 internally, Destroy rets non-zero */
570 ok(pFDSA_Destroy(&info), "FDSA_Destroy rets FALSE\n");
573 HeapFree(GetProcessHeap(), 0, mem);
577 typedef struct SHELL_USER_SID {
578 SID_IDENTIFIER_AUTHORITY sidAuthority;
579 DWORD dwUserGroupID;
580 DWORD dwUserID;
581 } SHELL_USER_SID, *PSHELL_USER_SID;
582 typedef struct SHELL_USER_PERMISSION {
583 SHELL_USER_SID susID;
584 DWORD dwAccessType;
585 BOOL fInherit;
586 DWORD dwAccessMask;
587 DWORD dwInheritMask;
588 DWORD dwInheritAccessMask;
589 } SHELL_USER_PERMISSION, *PSHELL_USER_PERMISSION;
590 static void test_GetShellSecurityDescriptor(void)
592 SHELL_USER_PERMISSION supCurrentUserFull = {
593 { {SECURITY_NULL_SID_AUTHORITY}, 0, 0 },
594 ACCESS_ALLOWED_ACE_TYPE, FALSE,
595 GENERIC_ALL, 0, 0 };
596 #define MY_INHERITANCE 0xBE /* invalid value to proof behavior */
597 SHELL_USER_PERMISSION supEveryoneDenied = {
598 { {SECURITY_WORLD_SID_AUTHORITY}, SECURITY_WORLD_RID, 0 },
599 ACCESS_DENIED_ACE_TYPE, TRUE,
600 GENERIC_WRITE, MY_INHERITANCE | 0xDEADBA00, GENERIC_READ };
601 PSHELL_USER_PERMISSION rgsup[2] = {
602 &supCurrentUserFull, &supEveryoneDenied,
604 SECURITY_DESCRIPTOR* psd;
605 SECURITY_DESCRIPTOR* (WINAPI*pGetShellSecurityDescriptor)(PSHELL_USER_PERMISSION*,int);
606 void *pChrCmpIW = GetProcAddress(hShlwapi, "ChrCmpIW");
608 pGetShellSecurityDescriptor=(void*)GetProcAddress(hShlwapi,(char*)475);
610 if(!pGetShellSecurityDescriptor)
612 win_skip("GetShellSecurityDescriptor not available\n");
613 return;
616 if(pChrCmpIW && pChrCmpIW == pGetShellSecurityDescriptor) /* win2k */
618 win_skip("Skipping for GetShellSecurityDescriptor, same ordinal used for ChrCmpIW\n");
619 return;
622 psd = pGetShellSecurityDescriptor(NULL, 2);
623 ok(psd==NULL ||
624 broken(psd==INVALID_HANDLE_VALUE), /* IE5 */
625 "GetShellSecurityDescriptor should fail\n");
626 psd = pGetShellSecurityDescriptor(rgsup, 0);
627 ok(psd==NULL, "GetShellSecurityDescriptor should fail, got %p\n", psd);
629 SetLastError(0xdeadbeef);
630 psd = pGetShellSecurityDescriptor(rgsup, 2);
631 if (psd == NULL && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
633 /* The previous calls to GetShellSecurityDescriptor don't set the last error */
634 win_skip("GetShellSecurityDescriptor is not implemented\n");
635 return;
637 if (psd == INVALID_HANDLE_VALUE)
639 win_skip("GetShellSecurityDescriptor is broken on IE5\n");
640 return;
642 ok(psd!=NULL, "GetShellSecurityDescriptor failed\n");
643 if (psd!=NULL)
645 BOOL bHasDacl = FALSE, bDefaulted, ret;
646 PACL pAcl;
647 DWORD dwRev;
648 SECURITY_DESCRIPTOR_CONTROL control;
650 ok(IsValidSecurityDescriptor(psd), "returned value is not valid SD\n");
652 ret = GetSecurityDescriptorControl(psd, &control, &dwRev);
653 ok(ret, "GetSecurityDescriptorControl failed with error %u\n", GetLastError());
654 ok(0 == (control & SE_SELF_RELATIVE), "SD should be absolute\n");
656 ret = GetSecurityDescriptorDacl(psd, &bHasDacl, &pAcl, &bDefaulted);
657 ok(ret, "GetSecurityDescriptorDacl failed with error %u\n", GetLastError());
659 ok(bHasDacl, "SD has no DACL\n");
660 if (bHasDacl)
662 ok(!bDefaulted, "DACL should not be defaulted\n");
664 ok(pAcl != NULL, "NULL DACL!\n");
665 if (pAcl != NULL)
667 ACL_SIZE_INFORMATION asiSize;
669 ok(IsValidAcl(pAcl), "DACL is not valid\n");
671 ret = GetAclInformation(pAcl, &asiSize, sizeof(asiSize), AclSizeInformation);
672 ok(ret, "GetAclInformation failed with error %u\n", GetLastError());
674 ok(asiSize.AceCount == 3, "Incorrect number of ACEs: %d entries\n", asiSize.AceCount);
675 if (asiSize.AceCount == 3)
677 ACCESS_ALLOWED_ACE *paaa; /* will use for DENIED too */
679 ret = GetAce(pAcl, 0, (LPVOID*)&paaa);
680 ok(ret, "GetAce failed with error %u\n", GetLastError());
681 ok(paaa->Header.AceType == ACCESS_ALLOWED_ACE_TYPE,
682 "Invalid ACE type %d\n", paaa->Header.AceType);
683 ok(paaa->Header.AceFlags == 0, "Invalid ACE flags %x\n", paaa->Header.AceFlags);
684 ok(paaa->Mask == GENERIC_ALL, "Invalid ACE mask %x\n", paaa->Mask);
686 ret = GetAce(pAcl, 1, (LPVOID*)&paaa);
687 ok(ret, "GetAce failed with error %u\n", GetLastError());
688 ok(paaa->Header.AceType == ACCESS_DENIED_ACE_TYPE,
689 "Invalid ACE type %d\n", paaa->Header.AceType);
690 /* first one of two ACEs generated from inheritable entry - without inheritance */
691 ok(paaa->Header.AceFlags == 0, "Invalid ACE flags %x\n", paaa->Header.AceFlags);
692 ok(paaa->Mask == GENERIC_WRITE, "Invalid ACE mask %x\n", paaa->Mask);
694 ret = GetAce(pAcl, 2, (LPVOID*)&paaa);
695 ok(ret, "GetAce failed with error %u\n", GetLastError());
696 ok(paaa->Header.AceType == ACCESS_DENIED_ACE_TYPE,
697 "Invalid ACE type %d\n", paaa->Header.AceType);
698 /* second ACE - with inheritance */
699 ok(paaa->Header.AceFlags == MY_INHERITANCE,
700 "Invalid ACE flags %x\n", paaa->Header.AceFlags);
701 ok(paaa->Mask == GENERIC_READ, "Invalid ACE mask %x\n", paaa->Mask);
706 LocalFree(psd);
710 static void test_SHPackDispParams(void)
712 DISPPARAMS params;
713 VARIANT vars[10];
714 HRESULT hres;
716 if(!pSHPackDispParams)
717 win_skip("SHPackSidpParams not available\n");
719 memset(&params, 0xc0, sizeof(params));
720 memset(vars, 0xc0, sizeof(vars));
721 hres = pSHPackDispParams(&params, vars, 1, VT_I4, 0xdeadbeef);
722 ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres);
723 ok(params.cArgs == 1, "params.cArgs = %d\n", params.cArgs);
724 ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
725 ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
726 ok(params.rgvarg == vars, "params.rgvarg = %p\n", params.rgvarg);
727 ok(V_VT(vars) == VT_I4, "V_VT(var) = %d\n", V_VT(vars));
728 ok(V_I4(vars) == 0xdeadbeef, "failed %x\n", V_I4(vars));
730 memset(&params, 0xc0, sizeof(params));
731 hres = pSHPackDispParams(&params, NULL, 0, 0);
732 ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres);
733 ok(params.cArgs == 0, "params.cArgs = %d\n", params.cArgs);
734 ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
735 ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
736 ok(params.rgvarg == NULL, "params.rgvarg = %p\n", params.rgvarg);
738 memset(vars, 0xc0, sizeof(vars));
739 memset(&params, 0xc0, sizeof(params));
740 hres = pSHPackDispParams(&params, vars, 4, VT_BSTR, (void*)0xdeadbeef, VT_EMPTY, 10,
741 VT_I4, 100, VT_DISPATCH, (void*)0xdeadbeef);
742 ok(hres == S_OK, "SHPackDispParams failed: %08x\n", hres);
743 ok(params.cArgs == 4, "params.cArgs = %d\n", params.cArgs);
744 ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
745 ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
746 ok(params.rgvarg == vars, "params.rgvarg = %p\n", params.rgvarg);
747 ok(V_VT(vars) == VT_DISPATCH, "V_VT(vars[0]) = %x\n", V_VT(vars));
748 ok(V_I4(vars) == 0xdeadbeef, "V_I4(vars[0]) = %x\n", V_I4(vars));
749 ok(V_VT(vars+1) == VT_I4, "V_VT(vars[1]) = %d\n", V_VT(vars+1));
750 ok(V_I4(vars+1) == 100, "V_I4(vars[1]) = %x\n", V_I4(vars+1));
751 ok(V_VT(vars+2) == VT_I4, "V_VT(vars[2]) = %d\n", V_VT(vars+2));
752 ok(V_I4(vars+2) == 10, "V_I4(vars[2]) = %x\n", V_I4(vars+2));
753 ok(V_VT(vars+3) == VT_BSTR, "V_VT(vars[3]) = %d\n", V_VT(vars+3));
754 ok(V_BSTR(vars+3) == (void*)0xdeadbeef, "V_BSTR(vars[3]) = %p\n", V_BSTR(vars+3));
757 typedef struct _disp
759 IDispatch IDispatch_iface;
760 LONG refCount;
761 } Disp;
763 static inline Disp *impl_from_IDispatch(IDispatch *iface)
765 return CONTAINING_RECORD(iface, Disp, IDispatch_iface);
768 typedef struct _contain
770 IConnectionPointContainer IConnectionPointContainer_iface;
771 LONG refCount;
773 UINT ptCount;
774 IConnectionPoint **pt;
775 } Contain;
777 static inline Contain *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
779 return CONTAINING_RECORD(iface, Contain, IConnectionPointContainer_iface);
782 typedef struct _cntptn
784 IConnectionPoint IConnectionPoint_iface;
785 LONG refCount;
787 Contain *container;
788 GUID id;
789 UINT sinkCount;
790 IUnknown **sink;
791 } ConPt;
793 static inline ConPt *impl_from_IConnectionPoint(IConnectionPoint *iface)
795 return CONTAINING_RECORD(iface, ConPt, IConnectionPoint_iface);
798 typedef struct _enum
800 IEnumConnections IEnumConnections_iface;
801 LONG refCount;
803 UINT idx;
804 ConPt *pt;
805 } EnumCon;
807 static inline EnumCon *impl_from_IEnumConnections(IEnumConnections *iface)
809 return CONTAINING_RECORD(iface, EnumCon, IEnumConnections_iface);
812 typedef struct _enumpt
814 IEnumConnectionPoints IEnumConnectionPoints_iface;
815 LONG refCount;
817 int idx;
818 Contain *container;
819 } EnumPt;
821 static inline EnumPt *impl_from_IEnumConnectionPoints(IEnumConnectionPoints *iface)
823 return CONTAINING_RECORD(iface, EnumPt, IEnumConnectionPoints_iface);
827 static HRESULT WINAPI Disp_QueryInterface(
828 IDispatch* This,
829 REFIID riid,
830 void **ppvObject)
832 *ppvObject = NULL;
834 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDispatch))
836 *ppvObject = This;
839 if (*ppvObject)
841 IDispatch_AddRef(This);
842 return S_OK;
845 trace("no interface\n");
846 return E_NOINTERFACE;
849 static ULONG WINAPI Disp_AddRef(IDispatch* This)
851 Disp *iface = impl_from_IDispatch(This);
852 return InterlockedIncrement(&iface->refCount);
855 static ULONG WINAPI Disp_Release(IDispatch* This)
857 Disp *iface = impl_from_IDispatch(This);
858 ULONG ret;
860 ret = InterlockedDecrement(&iface->refCount);
861 if (ret == 0)
862 HeapFree(GetProcessHeap(),0,This);
863 return ret;
866 static HRESULT WINAPI Disp_GetTypeInfoCount(
867 IDispatch* This,
868 UINT *pctinfo)
870 return ERROR_SUCCESS;
873 static HRESULT WINAPI Disp_GetTypeInfo(
874 IDispatch* This,
875 UINT iTInfo,
876 LCID lcid,
877 ITypeInfo **ppTInfo)
879 return ERROR_SUCCESS;
882 static HRESULT WINAPI Disp_GetIDsOfNames(
883 IDispatch* This,
884 REFIID riid,
885 LPOLESTR *rgszNames,
886 UINT cNames,
887 LCID lcid,
888 DISPID *rgDispId)
890 return ERROR_SUCCESS;
893 static HRESULT WINAPI Disp_Invoke(
894 IDispatch* This,
895 DISPID dispIdMember,
896 REFIID riid,
897 LCID lcid,
898 WORD wFlags,
899 DISPPARAMS *pDispParams,
900 VARIANT *pVarResult,
901 EXCEPINFO *pExcepInfo,
902 UINT *puArgErr)
904 trace("%p %x %p %x %x %p %p %p %p\n",This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
906 ok(dispIdMember == 0xa0 || dispIdMember == 0xa1, "Unknown dispIdMember\n");
907 ok(pDispParams != NULL, "Invoked with NULL pDispParams\n");
908 ok(wFlags == DISPATCH_METHOD, "Wrong flags %x\n",wFlags);
909 ok(lcid == 0,"Wrong lcid %x\n",lcid);
910 if (dispIdMember == 0xa0)
912 ok(pDispParams->cArgs == 0, "params.cArgs = %d\n", pDispParams->cArgs);
913 ok(pDispParams->cNamedArgs == 0, "params.cNamedArgs = %d\n", pDispParams->cArgs);
914 ok(pDispParams->rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", pDispParams->rgdispidNamedArgs);
915 ok(pDispParams->rgvarg == NULL, "params.rgvarg = %p\n", pDispParams->rgvarg);
917 else if (dispIdMember == 0xa1)
919 ok(pDispParams->cArgs == 2, "params.cArgs = %d\n", pDispParams->cArgs);
920 ok(pDispParams->cNamedArgs == 0, "params.cNamedArgs = %d\n", pDispParams->cArgs);
921 ok(pDispParams->rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", pDispParams->rgdispidNamedArgs);
922 ok(V_VT(pDispParams->rgvarg) == VT_BSTR, "V_VT(var) = %d\n", V_VT(pDispParams->rgvarg));
923 ok(V_I4(pDispParams->rgvarg) == 0xdeadcafe , "failed %p\n", V_BSTR(pDispParams->rgvarg));
924 ok(V_VT(pDispParams->rgvarg+1) == VT_I4, "V_VT(var) = %d\n", V_VT(pDispParams->rgvarg+1));
925 ok(V_I4(pDispParams->rgvarg+1) == 0xdeadbeef, "failed %x\n", V_I4(pDispParams->rgvarg+1));
928 return ERROR_SUCCESS;
931 static const IDispatchVtbl disp_vtbl = {
932 Disp_QueryInterface,
933 Disp_AddRef,
934 Disp_Release,
936 Disp_GetTypeInfoCount,
937 Disp_GetTypeInfo,
938 Disp_GetIDsOfNames,
939 Disp_Invoke
942 static HRESULT WINAPI Enum_QueryInterface(
943 IEnumConnections* This,
944 REFIID riid,
945 void **ppvObject)
947 *ppvObject = NULL;
949 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumConnections))
951 *ppvObject = This;
954 if (*ppvObject)
956 IEnumConnections_AddRef(This);
957 return S_OK;
960 trace("no interface\n");
961 return E_NOINTERFACE;
964 static ULONG WINAPI Enum_AddRef(IEnumConnections* This)
966 EnumCon *iface = impl_from_IEnumConnections(This);
967 return InterlockedIncrement(&iface->refCount);
970 static ULONG WINAPI Enum_Release(IEnumConnections* This)
972 EnumCon *iface = impl_from_IEnumConnections(This);
973 ULONG ret;
975 ret = InterlockedDecrement(&iface->refCount);
976 if (ret == 0)
977 HeapFree(GetProcessHeap(),0,This);
978 return ret;
981 static HRESULT WINAPI Enum_Next(
982 IEnumConnections* This,
983 ULONG cConnections,
984 LPCONNECTDATA rgcd,
985 ULONG *pcFetched)
987 EnumCon *iface = impl_from_IEnumConnections(This);
989 if (cConnections > 0 && iface->idx < iface->pt->sinkCount)
991 rgcd->pUnk = iface->pt->sink[iface->idx];
992 IUnknown_AddRef(iface->pt->sink[iface->idx]);
993 rgcd->dwCookie=0xff;
994 if (pcFetched)
995 *pcFetched = 1;
996 iface->idx++;
997 return S_OK;
1000 return E_FAIL;
1003 static HRESULT WINAPI Enum_Skip(
1004 IEnumConnections* This,
1005 ULONG cConnections)
1007 return E_FAIL;
1010 static HRESULT WINAPI Enum_Reset(
1011 IEnumConnections* This)
1013 return E_FAIL;
1016 static HRESULT WINAPI Enum_Clone(
1017 IEnumConnections* This,
1018 IEnumConnections **ppEnum)
1020 return E_FAIL;
1023 static const IEnumConnectionsVtbl enum_vtbl = {
1025 Enum_QueryInterface,
1026 Enum_AddRef,
1027 Enum_Release,
1028 Enum_Next,
1029 Enum_Skip,
1030 Enum_Reset,
1031 Enum_Clone
1034 static HRESULT WINAPI ConPt_QueryInterface(
1035 IConnectionPoint* This,
1036 REFIID riid,
1037 void **ppvObject)
1039 *ppvObject = NULL;
1041 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IConnectionPoint))
1043 *ppvObject = This;
1046 if (*ppvObject)
1048 IConnectionPoint_AddRef(This);
1049 return S_OK;
1052 trace("no interface\n");
1053 return E_NOINTERFACE;
1056 static ULONG WINAPI ConPt_AddRef(
1057 IConnectionPoint* This)
1059 ConPt *iface = impl_from_IConnectionPoint(This);
1060 return InterlockedIncrement(&iface->refCount);
1063 static ULONG WINAPI ConPt_Release(
1064 IConnectionPoint* This)
1066 ConPt *iface = impl_from_IConnectionPoint(This);
1067 ULONG ret;
1069 ret = InterlockedDecrement(&iface->refCount);
1070 if (ret == 0)
1072 if (iface->sinkCount > 0)
1074 int i;
1075 for (i = 0; i < iface->sinkCount; i++)
1077 if (iface->sink[i])
1078 IUnknown_Release(iface->sink[i]);
1080 HeapFree(GetProcessHeap(),0,iface->sink);
1082 HeapFree(GetProcessHeap(),0,This);
1084 return ret;
1087 static HRESULT WINAPI ConPt_GetConnectionInterface(
1088 IConnectionPoint* This,
1089 IID *pIID)
1091 static int i = 0;
1092 ConPt *iface = impl_from_IConnectionPoint(This);
1093 if (i==0)
1095 i++;
1096 return E_FAIL;
1098 else
1099 memcpy(pIID,&iface->id,sizeof(GUID));
1100 return S_OK;
1103 static HRESULT WINAPI ConPt_GetConnectionPointContainer(
1104 IConnectionPoint* This,
1105 IConnectionPointContainer **ppCPC)
1107 ConPt *iface = impl_from_IConnectionPoint(This);
1109 *ppCPC = &iface->container->IConnectionPointContainer_iface;
1110 return S_OK;
1113 static HRESULT WINAPI ConPt_Advise(
1114 IConnectionPoint* This,
1115 IUnknown *pUnkSink,
1116 DWORD *pdwCookie)
1118 ConPt *iface = impl_from_IConnectionPoint(This);
1120 if (iface->sinkCount == 0)
1121 iface->sink = HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown*));
1122 else
1123 iface->sink = HeapReAlloc(GetProcessHeap(),0,iface->sink,sizeof(IUnknown*)*(iface->sinkCount+1));
1124 iface->sink[iface->sinkCount] = pUnkSink;
1125 IUnknown_AddRef(pUnkSink);
1126 iface->sinkCount++;
1127 *pdwCookie = iface->sinkCount;
1128 return S_OK;
1131 static HRESULT WINAPI ConPt_Unadvise(
1132 IConnectionPoint* This,
1133 DWORD dwCookie)
1135 ConPt *iface = impl_from_IConnectionPoint(This);
1137 if (dwCookie > iface->sinkCount)
1138 return E_FAIL;
1139 else
1141 IUnknown_Release(iface->sink[dwCookie-1]);
1142 iface->sink[dwCookie-1] = NULL;
1144 return S_OK;
1147 static HRESULT WINAPI ConPt_EnumConnections(
1148 IConnectionPoint* This,
1149 IEnumConnections **ppEnum)
1151 EnumCon *ec;
1153 ec = HeapAlloc(GetProcessHeap(),0,sizeof(EnumCon));
1154 ec->IEnumConnections_iface.lpVtbl = &enum_vtbl;
1155 ec->refCount = 1;
1156 ec->pt = impl_from_IConnectionPoint(This);
1157 ec->idx = 0;
1158 *ppEnum = &ec->IEnumConnections_iface;
1160 return S_OK;
1163 static const IConnectionPointVtbl point_vtbl = {
1164 ConPt_QueryInterface,
1165 ConPt_AddRef,
1166 ConPt_Release,
1168 ConPt_GetConnectionInterface,
1169 ConPt_GetConnectionPointContainer,
1170 ConPt_Advise,
1171 ConPt_Unadvise,
1172 ConPt_EnumConnections
1175 static HRESULT WINAPI EnumPt_QueryInterface(
1176 IEnumConnectionPoints* This,
1177 REFIID riid,
1178 void **ppvObject)
1180 *ppvObject = NULL;
1182 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumConnectionPoints))
1184 *ppvObject = This;
1187 if (*ppvObject)
1189 IEnumConnectionPoints_AddRef(This);
1190 return S_OK;
1193 trace("no interface\n");
1194 return E_NOINTERFACE;
1197 static ULONG WINAPI EnumPt_AddRef(IEnumConnectionPoints* This)
1199 EnumPt *iface = impl_from_IEnumConnectionPoints(This);
1200 return InterlockedIncrement(&iface->refCount);
1203 static ULONG WINAPI EnumPt_Release(IEnumConnectionPoints* This)
1205 EnumPt *iface = impl_from_IEnumConnectionPoints(This);
1206 ULONG ret;
1208 ret = InterlockedDecrement(&iface->refCount);
1209 if (ret == 0)
1210 HeapFree(GetProcessHeap(),0,This);
1211 return ret;
1214 static HRESULT WINAPI EnumPt_Next(
1215 IEnumConnectionPoints* This,
1216 ULONG cConnections,
1217 IConnectionPoint **rgcd,
1218 ULONG *pcFetched)
1220 EnumPt *iface = impl_from_IEnumConnectionPoints(This);
1222 if (cConnections > 0 && iface->idx < iface->container->ptCount)
1224 *rgcd = iface->container->pt[iface->idx];
1225 IConnectionPoint_AddRef(iface->container->pt[iface->idx]);
1226 if (pcFetched)
1227 *pcFetched = 1;
1228 iface->idx++;
1229 return S_OK;
1232 return E_FAIL;
1235 static HRESULT WINAPI EnumPt_Skip(
1236 IEnumConnectionPoints* This,
1237 ULONG cConnections)
1239 return E_FAIL;
1242 static HRESULT WINAPI EnumPt_Reset(
1243 IEnumConnectionPoints* This)
1245 return E_FAIL;
1248 static HRESULT WINAPI EnumPt_Clone(
1249 IEnumConnectionPoints* This,
1250 IEnumConnectionPoints **ppEnumPt)
1252 return E_FAIL;
1255 static const IEnumConnectionPointsVtbl enumpt_vtbl = {
1257 EnumPt_QueryInterface,
1258 EnumPt_AddRef,
1259 EnumPt_Release,
1260 EnumPt_Next,
1261 EnumPt_Skip,
1262 EnumPt_Reset,
1263 EnumPt_Clone
1266 static HRESULT WINAPI Contain_QueryInterface(
1267 IConnectionPointContainer* This,
1268 REFIID riid,
1269 void **ppvObject)
1271 *ppvObject = NULL;
1273 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IConnectionPointContainer))
1275 *ppvObject = This;
1278 if (*ppvObject)
1280 IConnectionPointContainer_AddRef(This);
1281 return S_OK;
1284 trace("no interface\n");
1285 return E_NOINTERFACE;
1288 static ULONG WINAPI Contain_AddRef(
1289 IConnectionPointContainer* This)
1291 Contain *iface = impl_from_IConnectionPointContainer(This);
1292 return InterlockedIncrement(&iface->refCount);
1295 static ULONG WINAPI Contain_Release(
1296 IConnectionPointContainer* This)
1298 Contain *iface = impl_from_IConnectionPointContainer(This);
1299 ULONG ret;
1301 ret = InterlockedDecrement(&iface->refCount);
1302 if (ret == 0)
1304 if (iface->ptCount > 0)
1306 int i;
1307 for (i = 0; i < iface->ptCount; i++)
1308 IConnectionPoint_Release(iface->pt[i]);
1309 HeapFree(GetProcessHeap(),0,iface->pt);
1311 HeapFree(GetProcessHeap(),0,This);
1313 return ret;
1316 static HRESULT WINAPI Contain_EnumConnectionPoints(
1317 IConnectionPointContainer* This,
1318 IEnumConnectionPoints **ppEnum)
1320 EnumPt *ec;
1322 ec = HeapAlloc(GetProcessHeap(),0,sizeof(EnumPt));
1323 ec->IEnumConnectionPoints_iface.lpVtbl = &enumpt_vtbl;
1324 ec->refCount = 1;
1325 ec->idx= 0;
1326 ec->container = impl_from_IConnectionPointContainer(This);
1327 *ppEnum = &ec->IEnumConnectionPoints_iface;
1329 return S_OK;
1332 static HRESULT WINAPI Contain_FindConnectionPoint(
1333 IConnectionPointContainer* This,
1334 REFIID riid,
1335 IConnectionPoint **ppCP)
1337 Contain *iface = impl_from_IConnectionPointContainer(This);
1338 ConPt *pt;
1340 if (!IsEqualIID(riid, &IID_NULL) || iface->ptCount ==0)
1342 pt = HeapAlloc(GetProcessHeap(),0,sizeof(ConPt));
1343 pt->IConnectionPoint_iface.lpVtbl = &point_vtbl;
1344 pt->refCount = 1;
1345 pt->sinkCount = 0;
1346 pt->sink = NULL;
1347 pt->container = iface;
1348 pt->id = IID_IDispatch;
1350 if (iface->ptCount == 0)
1351 iface->pt =HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown*));
1352 else
1353 iface->pt = HeapReAlloc(GetProcessHeap(),0,iface->pt,sizeof(IUnknown*)*(iface->ptCount+1));
1354 iface->pt[iface->ptCount] = &pt->IConnectionPoint_iface;
1355 iface->ptCount++;
1357 *ppCP = &pt->IConnectionPoint_iface;
1359 else
1361 *ppCP = iface->pt[0];
1362 IUnknown_AddRef((IUnknown*)*ppCP);
1365 return S_OK;
1368 static const IConnectionPointContainerVtbl contain_vtbl = {
1369 Contain_QueryInterface,
1370 Contain_AddRef,
1371 Contain_Release,
1373 Contain_EnumConnectionPoints,
1374 Contain_FindConnectionPoint
1377 static void test_IConnectionPoint(void)
1379 HRESULT rc;
1380 ULONG ref;
1381 IConnectionPoint *point;
1382 Contain *container;
1383 Disp *dispatch;
1384 DWORD cookie = 0xffffffff;
1385 DISPPARAMS params;
1386 VARIANT vars[10];
1388 if (!pIConnectionPoint_SimpleInvoke || !pConnectToConnectionPoint)
1390 win_skip("IConnectionPoint Apis not present\n");
1391 return;
1394 container = HeapAlloc(GetProcessHeap(),0,sizeof(Contain));
1395 container->IConnectionPointContainer_iface.lpVtbl = &contain_vtbl;
1396 container->refCount = 1;
1397 container->ptCount = 0;
1398 container->pt = NULL;
1400 dispatch = HeapAlloc(GetProcessHeap(),0,sizeof(Disp));
1401 dispatch->IDispatch_iface.lpVtbl = &disp_vtbl;
1402 dispatch->refCount = 1;
1404 rc = pConnectToConnectionPoint((IUnknown*)dispatch, &IID_NULL, TRUE, (IUnknown*)container, &cookie, &point);
1405 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1406 ok(point != NULL, "returned ConnectionPoint is NULL\n");
1407 ok(cookie != 0xffffffff, "invalid cookie returned\n");
1409 rc = pIConnectionPoint_SimpleInvoke(point,0xa0,NULL);
1410 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1412 if (pSHPackDispParams)
1414 memset(&params, 0xc0, sizeof(params));
1415 memset(vars, 0xc0, sizeof(vars));
1416 rc = pSHPackDispParams(&params, vars, 2, VT_I4, 0xdeadbeef, VT_BSTR, 0xdeadcafe);
1417 ok(rc == S_OK, "SHPackDispParams failed: %08x\n", rc);
1419 rc = pIConnectionPoint_SimpleInvoke(point,0xa1,&params);
1420 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1422 else
1423 win_skip("pSHPackDispParams not present\n");
1425 rc = pConnectToConnectionPoint(NULL, &IID_NULL, FALSE, (IUnknown*)container, &cookie, NULL);
1426 ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
1428 /* MSDN says this should be required but it crashs on XP
1429 IUnknown_Release(point);
1431 ref = IUnknown_Release((IUnknown*)container);
1432 ok(ref == 0, "leftover IConnectionPointContainer reference %i\n",ref);
1433 ref = IUnknown_Release((IUnknown*)dispatch);
1434 ok(ref == 0, "leftover IDispatch reference %i\n",ref);
1437 typedef struct _propbag
1439 IPropertyBag IPropertyBag_iface;
1440 LONG refCount;
1442 } PropBag;
1444 static inline PropBag *impl_from_IPropertyBag(IPropertyBag *iface)
1446 return CONTAINING_RECORD(iface, PropBag, IPropertyBag_iface);
1450 static HRESULT WINAPI Prop_QueryInterface(
1451 IPropertyBag* This,
1452 REFIID riid,
1453 void **ppvObject)
1455 *ppvObject = NULL;
1457 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPropertyBag))
1459 *ppvObject = This;
1462 if (*ppvObject)
1464 IPropertyBag_AddRef(This);
1465 return S_OK;
1468 trace("no interface\n");
1469 return E_NOINTERFACE;
1472 static ULONG WINAPI Prop_AddRef(
1473 IPropertyBag* This)
1475 PropBag *iface = impl_from_IPropertyBag(This);
1476 return InterlockedIncrement(&iface->refCount);
1479 static ULONG WINAPI Prop_Release(
1480 IPropertyBag* This)
1482 PropBag *iface = impl_from_IPropertyBag(This);
1483 ULONG ret;
1485 ret = InterlockedDecrement(&iface->refCount);
1486 if (ret == 0)
1487 HeapFree(GetProcessHeap(),0,This);
1488 return ret;
1491 static HRESULT WINAPI Prop_Read(
1492 IPropertyBag* This,
1493 LPCOLESTR pszPropName,
1494 VARIANT *pVar,
1495 IErrorLog *pErrorLog)
1497 V_VT(pVar) = VT_BLOB|VT_BYREF;
1498 V_BYREF(pVar) = (LPVOID)0xdeadcafe;
1499 return S_OK;
1502 static HRESULT WINAPI Prop_Write(
1503 IPropertyBag* This,
1504 LPCOLESTR pszPropName,
1505 VARIANT *pVar)
1507 return S_OK;
1511 static const IPropertyBagVtbl prop_vtbl = {
1512 Prop_QueryInterface,
1513 Prop_AddRef,
1514 Prop_Release,
1516 Prop_Read,
1517 Prop_Write
1520 static void test_SHPropertyBag_ReadLONG(void)
1522 PropBag *pb;
1523 HRESULT rc;
1524 LONG out;
1525 static const WCHAR szName1[] = {'n','a','m','e','1',0};
1527 if (!pSHPropertyBag_ReadLONG)
1529 win_skip("SHPropertyBag_ReadLONG not present\n");
1530 return;
1533 pb = HeapAlloc(GetProcessHeap(),0,sizeof(PropBag));
1534 pb->refCount = 1;
1535 pb->IPropertyBag_iface.lpVtbl = &prop_vtbl;
1537 out = 0xfeedface;
1538 rc = pSHPropertyBag_ReadLONG(NULL, szName1, &out);
1539 ok(rc == E_INVALIDARG || broken(rc == 0), "incorrect return %x\n",rc);
1540 ok(out == 0xfeedface, "value should not have changed\n");
1541 rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, NULL, &out);
1542 ok(rc == E_INVALIDARG || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
1543 ok(out == 0xfeedface, "value should not have changed\n");
1544 rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, szName1, NULL);
1545 ok(rc == E_INVALIDARG || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
1546 rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, szName1, &out);
1547 ok(rc == DISP_E_BADVARTYPE || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
1548 ok(out == 0xfeedface || broken(out == 0xfeedfa00), "value should not have changed %x\n",out);
1549 IUnknown_Release((IUnknown*)pb);
1554 static void test_SHSetWindowBits(void)
1556 HWND hwnd;
1557 DWORD style, styleold;
1558 WNDCLASSA clsA;
1560 if(!pSHSetWindowBits)
1562 win_skip("SHSetWindowBits is not available\n");
1563 return;
1566 clsA.style = 0;
1567 clsA.lpfnWndProc = DefWindowProcA;
1568 clsA.cbClsExtra = 0;
1569 clsA.cbWndExtra = 0;
1570 clsA.hInstance = GetModuleHandleA(NULL);
1571 clsA.hIcon = 0;
1572 clsA.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
1573 clsA.hbrBackground = NULL;
1574 clsA.lpszMenuName = NULL;
1575 clsA.lpszClassName = "Shlwapi test class";
1576 RegisterClassA(&clsA);
1578 hwnd = CreateWindowA("Shlwapi test class", "Test", WS_VISIBLE, 0, 0, 100, 100,
1579 NULL, NULL, GetModuleHandleA(NULL), 0);
1580 ok(IsWindow(hwnd), "failed to create window\n");
1582 /* null window */
1583 SetLastError(0xdeadbeef);
1584 style = pSHSetWindowBits(NULL, GWL_STYLE, 0, 0);
1585 ok(style == 0, "expected 0 retval, got %d\n", style);
1586 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
1587 broken(GetLastError() == 0xdeadbeef), /* Win9x/WinMe */
1588 "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
1590 /* zero mask, zero flags */
1591 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1592 style = pSHSetWindowBits(hwnd, GWL_STYLE, 0, 0);
1593 ok(styleold == style, "expected old style\n");
1594 ok(styleold == GetWindowLongA(hwnd, GWL_STYLE), "expected to keep old style\n");
1596 /* test mask */
1597 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1598 ok(styleold & WS_VISIBLE, "expected WS_VISIBLE\n");
1599 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1601 ok(style == styleold, "expected previous style, got %x\n", style);
1602 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1604 /* test mask, unset style bit used */
1605 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1606 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1607 ok(style == styleold, "expected previous style, got %x\n", style);
1608 ok(styleold == GetWindowLongA(hwnd, GWL_STYLE), "expected to keep old style\n");
1610 /* set back with flags */
1611 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1612 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, WS_VISIBLE);
1613 ok(style == styleold, "expected previous style, got %x\n", style);
1614 ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "expected updated style\n");
1616 /* reset and try to set without a mask */
1617 pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1618 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1619 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1620 style = pSHSetWindowBits(hwnd, GWL_STYLE, 0, WS_VISIBLE);
1621 ok(style == styleold, "expected previous style, got %x\n", style);
1622 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1624 DestroyWindow(hwnd);
1626 UnregisterClassA("Shlwapi test class", GetModuleHandleA(NULL));
1629 static void test_SHFormatDateTimeA(void)
1631 FILETIME UNALIGNED filetime;
1632 CHAR buff[100], buff2[100], buff3[100];
1633 SYSTEMTIME st;
1634 DWORD flags;
1635 INT ret;
1637 if(!pSHFormatDateTimeA)
1639 win_skip("pSHFormatDateTimeA isn't available\n");
1640 return;
1643 if (0)
1645 /* crashes on native */
1646 pSHFormatDateTimeA(NULL, NULL, NULL, 0);
1649 GetLocalTime(&st);
1650 SystemTimeToFileTime(&st, &filetime);
1651 /* SHFormatDateTime expects input as utc */
1652 LocalFileTimeToFileTime(&filetime, &filetime);
1654 /* no way to get required buffer length here */
1655 SetLastError(0xdeadbeef);
1656 ret = pSHFormatDateTimeA(&filetime, NULL, NULL, 0);
1657 ok(ret == 0, "got %d\n", ret);
1658 ok(GetLastError() == 0xdeadbeef || broken(GetLastError() == ERROR_SUCCESS /* Win7 */),
1659 "expected 0xdeadbeef, got %d\n", GetLastError());
1661 SetLastError(0xdeadbeef);
1662 buff[0] = 'a'; buff[1] = 0;
1663 ret = pSHFormatDateTimeA(&filetime, NULL, buff, 0);
1664 ok(ret == 0, "got %d\n", ret);
1665 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1666 ok(buff[0] == 'a', "expected same string, got %s\n", buff);
1668 /* flags needs to have FDTF_NOAUTOREADINGORDER for these tests to succeed on Vista+ */
1670 /* all combinations documented as invalid succeeded */
1671 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTTIME | FDTF_LONGTIME;
1672 SetLastError(0xdeadbeef);
1673 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1674 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1675 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1677 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_LONGDATE;
1678 SetLastError(0xdeadbeef);
1679 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1680 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1681 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1683 flags = FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE;
1684 SetLastError(0xdeadbeef);
1685 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1686 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1687 ok(GetLastError() == 0xdeadbeef ||
1688 broken(GetLastError() == ERROR_INVALID_FLAGS), /* Win9x/WinMe */
1689 "expected 0xdeadbeef, got %d\n", GetLastError());
1691 /* now check returned strings */
1692 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTTIME;
1693 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1694 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1695 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff2, sizeof(buff2));
1696 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1697 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1699 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGTIME;
1700 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1701 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1702 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2));
1703 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1704 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1706 /* both time flags */
1707 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGTIME | FDTF_SHORTTIME;
1708 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1709 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1710 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2));
1711 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1712 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1714 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE;
1715 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1716 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1717 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1718 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1719 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1721 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE;
1722 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1723 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1724 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1725 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1726 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1728 /* both date flags */
1729 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_SHORTDATE;
1730 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1731 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1732 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1733 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1734 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1736 /* various combinations of date/time flags */
1737 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_SHORTTIME;
1738 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1739 ok(ret == lstrlenA(buff)+1, "got %d, length %d\n", ret, lstrlenA(buff)+1);
1740 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3));
1741 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1742 ok(lstrcmpA(buff3, buff + lstrlenA(buff) - lstrlenA(buff3)) == 0,
1743 "expected (%s), got (%s) for time part\n",
1744 buff3, buff + lstrlenA(buff) - lstrlenA(buff3));
1745 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1746 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1747 buff[lstrlenA(buff2)] = '\0';
1748 ok(lstrcmpA(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1749 buff2, buff);
1751 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_LONGTIME;
1752 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1753 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1754 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3));
1755 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1756 ok(lstrcmpA(buff3, buff + lstrlenA(buff) - lstrlenA(buff3)) == 0,
1757 "expected (%s), got (%s) for time part\n",
1758 buff3, buff + lstrlenA(buff) - lstrlenA(buff3));
1759 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
1760 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1761 buff[lstrlenA(buff2)] = '\0';
1762 ok(lstrcmpA(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1763 buff2, buff);
1765 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_SHORTTIME;
1766 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1767 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1768 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1769 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1770 strcat(buff2, " ");
1771 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3));
1772 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1773 strcat(buff2, buff3);
1774 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1776 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_LONGTIME;
1777 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1778 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1779 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
1780 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1781 strcat(buff2, " ");
1782 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3));
1783 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1784 strcat(buff2, buff3);
1785 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1788 static void test_SHFormatDateTimeW(void)
1790 FILETIME UNALIGNED filetime;
1791 WCHAR buff[100], buff2[100], buff3[100], *p1, *p2;
1792 SYSTEMTIME st;
1793 DWORD flags;
1794 INT ret;
1795 static const WCHAR spaceW[] = {' ',0};
1796 #define UNICODE_LTR_MARK 0x200e
1797 #define UNICODE_RTL_MARK 0x200f
1799 if(!pSHFormatDateTimeW)
1801 win_skip("pSHFormatDateTimeW isn't available\n");
1802 return;
1805 if (0)
1807 /* crashes on native */
1808 pSHFormatDateTimeW(NULL, NULL, NULL, 0);
1811 GetLocalTime(&st);
1812 SystemTimeToFileTime(&st, &filetime);
1813 /* SHFormatDateTime expects input as utc */
1814 LocalFileTimeToFileTime(&filetime, &filetime);
1816 /* no way to get required buffer length here */
1817 SetLastError(0xdeadbeef);
1818 ret = pSHFormatDateTimeW(&filetime, NULL, NULL, 0);
1819 ok(ret == 0, "expected 0, got %d\n", ret);
1820 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1822 SetLastError(0xdeadbeef);
1823 buff[0] = 'a'; buff[1] = 0;
1824 ret = pSHFormatDateTimeW(&filetime, NULL, buff, 0);
1825 ok(ret == 0, "expected 0, got %d\n", ret);
1826 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1827 ok(buff[0] == 'a', "expected same string\n");
1829 /* all combinations documented as invalid succeeded */
1830 flags = FDTF_SHORTTIME | FDTF_LONGTIME;
1831 SetLastError(0xdeadbeef);
1832 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1833 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1834 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1835 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1837 flags = FDTF_SHORTDATE | FDTF_LONGDATE;
1838 SetLastError(0xdeadbeef);
1839 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1840 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1841 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1842 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1844 flags = FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE;
1845 SetLastError(0xdeadbeef);
1846 buff[0] = 0; /* NT4 doesn't clear the buffer on failure */
1847 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1848 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1849 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1850 ok(GetLastError() == 0xdeadbeef ||
1851 broken(GetLastError() == ERROR_INVALID_FLAGS), /* Win9x/WinMe/NT4 */
1852 "expected 0xdeadbeef, got %d\n", GetLastError());
1854 /* now check returned strings */
1855 flags = FDTF_SHORTTIME;
1856 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1857 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1858 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1859 SetLastError(0xdeadbeef);
1860 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1861 if (ret == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1863 win_skip("Needed W-functions are not implemented\n");
1864 return;
1866 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1867 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1869 flags = FDTF_LONGTIME;
1870 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1871 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1872 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1873 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1874 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1875 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1877 /* both time flags */
1878 flags = FDTF_LONGTIME | FDTF_SHORTTIME;
1879 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1880 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1881 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1882 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1883 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1884 ok(lstrcmpW(buff, buff2) == 0, "expected equal string\n");
1886 flags = FDTF_SHORTDATE;
1887 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1888 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1889 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1890 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1891 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1892 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1894 flags = FDTF_LONGDATE;
1895 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1896 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1897 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1898 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1899 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1900 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1902 /* both date flags */
1903 flags = FDTF_LONGDATE | FDTF_SHORTDATE;
1904 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1905 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1906 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1907 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1908 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1909 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1911 /* various combinations of date/time flags */
1912 flags = FDTF_LONGDATE | FDTF_SHORTTIME;
1913 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1914 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1915 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1916 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1917 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1918 ok(lstrcmpW(buff3, buff + lstrlenW(buff) - lstrlenW(buff3)) == 0,
1919 "expected (%s), got (%s) for time part\n",
1920 wine_dbgstr_w(buff3), wine_dbgstr_w(buff + lstrlenW(buff) - lstrlenW(buff3)));
1921 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1922 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1923 p1 = buff;
1924 p2 = buff2;
1925 while (*p2 != '\0')
1927 while (*p1 == UNICODE_LTR_MARK || *p1 == UNICODE_RTL_MARK)
1928 p1++;
1929 while (*p2 == UNICODE_LTR_MARK || *p2 == UNICODE_RTL_MARK)
1930 p2++;
1931 p1++;
1932 p2++;
1934 *p1 = '\0';
1935 ok(lstrcmpW(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1936 wine_dbgstr_w(buff2), wine_dbgstr_w(buff));
1938 flags = FDTF_LONGDATE | FDTF_LONGTIME;
1939 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1940 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1941 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1942 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1943 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1944 ok(lstrcmpW(buff3, buff + lstrlenW(buff) - lstrlenW(buff3)) == 0,
1945 "expected (%s), got (%s) for time part\n",
1946 wine_dbgstr_w(buff3), wine_dbgstr_w(buff + lstrlenW(buff) - lstrlenW(buff3)));
1947 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1948 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1949 p1 = buff;
1950 p2 = buff2;
1951 while (*p2 != '\0')
1953 while (*p1 == UNICODE_LTR_MARK || *p1 == UNICODE_RTL_MARK)
1954 p1++;
1955 while (*p2 == UNICODE_LTR_MARK || *p2 == UNICODE_RTL_MARK)
1956 p2++;
1957 p1++;
1958 p2++;
1960 *p1 = '\0';
1961 ok(lstrcmpW(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1962 wine_dbgstr_w(buff2), wine_dbgstr_w(buff));
1964 flags = FDTF_SHORTDATE | FDTF_SHORTTIME;
1965 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1966 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1967 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1968 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1969 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1970 lstrcatW(buff2, spaceW);
1971 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1972 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1973 lstrcatW(buff2, buff3);
1974 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1976 flags = FDTF_SHORTDATE | FDTF_LONGTIME;
1977 ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
1978 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1979 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1980 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
1981 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1982 lstrcatW(buff2, spaceW);
1983 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
1984 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1985 lstrcatW(buff2, buff3);
1986 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1989 static void test_SHGetObjectCompatFlags(void)
1991 struct compat_value {
1992 CHAR nameA[30];
1993 DWORD value;
1996 struct compat_value values[] = {
1997 { "OTNEEDSSFCACHE", 0x1 },
1998 { "NO_WEBVIEW", 0x2 },
1999 { "UNBINDABLE", 0x4 },
2000 { "PINDLL", 0x8 },
2001 { "NEEDSFILESYSANCESTOR", 0x10 },
2002 { "NOTAFILESYSTEM", 0x20 },
2003 { "CTXMENU_NOVERBS", 0x40 },
2004 { "CTXMENU_LIMITEDQI", 0x80 },
2005 { "COCREATESHELLFOLDERONLY", 0x100 },
2006 { "NEEDSSTORAGEANCESTOR", 0x200 },
2007 { "NOLEGACYWEBVIEW", 0x400 },
2008 { "CTXMENU_XPQCMFLAGS", 0x1000 },
2009 { "NOIPROPERTYSTORE", 0x2000 }
2012 static const char compat_path[] = "Software\\Microsoft\\Windows\\CurrentVersion\\ShellCompatibility\\Objects";
2013 void *pColorAdjustLuma = GetProcAddress(hShlwapi, "ColorAdjustLuma");
2014 CHAR keyA[39]; /* {CLSID} */
2015 HKEY root;
2016 DWORD ret;
2017 int i;
2019 if (!pSHGetObjectCompatFlags)
2021 win_skip("SHGetObjectCompatFlags isn't available\n");
2022 return;
2025 if (pColorAdjustLuma && pColorAdjustLuma == pSHGetObjectCompatFlags) /* win2k */
2027 win_skip("Skipping SHGetObjectCompatFlags, same ordinal used for ColorAdjustLuma\n");
2028 return;
2031 /* null args */
2032 ret = pSHGetObjectCompatFlags(NULL, NULL);
2033 ok(ret == 0, "got %d\n", ret);
2035 ret = RegOpenKeyA(HKEY_LOCAL_MACHINE, compat_path, &root);
2036 if (ret != ERROR_SUCCESS)
2038 skip("No compatibility class data found\n");
2039 return;
2042 for (i = 0; RegEnumKeyA(root, i, keyA, sizeof(keyA)) == ERROR_SUCCESS; i++)
2044 HKEY clsid_key;
2046 if (RegOpenKeyA(root, keyA, &clsid_key) == ERROR_SUCCESS)
2048 CHAR valueA[30];
2049 DWORD expected = 0, got, length = sizeof(valueA);
2050 CLSID clsid;
2051 int v;
2053 for (v = 0; RegEnumValueA(clsid_key, v, valueA, &length, NULL, NULL, NULL, NULL) == ERROR_SUCCESS; v++)
2055 int j;
2057 for (j = 0; j < sizeof(values)/sizeof(struct compat_value); j++)
2058 if (lstrcmpA(values[j].nameA, valueA) == 0)
2060 expected |= values[j].value;
2061 break;
2064 length = sizeof(valueA);
2067 pGUIDFromStringA(keyA, &clsid);
2068 got = pSHGetObjectCompatFlags(NULL, &clsid);
2069 ok(got == expected, "got 0x%08x, expected 0x%08x. Key %s\n", got, expected, keyA);
2071 RegCloseKey(clsid_key);
2075 RegCloseKey(root);
2078 typedef struct {
2079 IOleCommandTarget IOleCommandTarget_iface;
2080 LONG ref;
2081 } IOleCommandTargetImpl;
2083 static inline IOleCommandTargetImpl *impl_from_IOleCommandTarget(IOleCommandTarget *iface)
2085 return CONTAINING_RECORD(iface, IOleCommandTargetImpl, IOleCommandTarget_iface);
2088 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl;
2090 static IOleCommandTarget* IOleCommandTargetImpl_Construct(void)
2092 IOleCommandTargetImpl *obj;
2094 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2095 obj->IOleCommandTarget_iface.lpVtbl = &IOleCommandTargetImpl_Vtbl;
2096 obj->ref = 1;
2098 return &obj->IOleCommandTarget_iface;
2101 static HRESULT WINAPI IOleCommandTargetImpl_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppvObj)
2103 IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface);
2105 if (IsEqualIID(riid, &IID_IUnknown) ||
2106 IsEqualIID(riid, &IID_IOleCommandTarget))
2108 *ppvObj = This;
2111 if(*ppvObj)
2113 IOleCommandTarget_AddRef(iface);
2114 return S_OK;
2117 return E_NOINTERFACE;
2120 static ULONG WINAPI IOleCommandTargetImpl_AddRef(IOleCommandTarget *iface)
2122 IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface);
2123 return InterlockedIncrement(&This->ref);
2126 static ULONG WINAPI IOleCommandTargetImpl_Release(IOleCommandTarget *iface)
2128 IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface);
2129 ULONG ref = InterlockedDecrement(&This->ref);
2131 if (!ref)
2133 HeapFree(GetProcessHeap(), 0, This);
2134 return 0;
2136 return ref;
2139 static HRESULT WINAPI IOleCommandTargetImpl_QueryStatus(
2140 IOleCommandTarget *iface, const GUID *group, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText)
2142 return E_NOTIMPL;
2145 static HRESULT WINAPI IOleCommandTargetImpl_Exec(
2146 IOleCommandTarget *iface,
2147 const GUID *CmdGroup,
2148 DWORD nCmdID,
2149 DWORD nCmdexecopt,
2150 VARIANT *pvaIn,
2151 VARIANT *pvaOut)
2153 add_call(&trace_got, 3, CmdGroup, (void*)(DWORD_PTR)nCmdID, (void*)(DWORD_PTR)nCmdexecopt, pvaIn, pvaOut);
2154 return S_OK;
2157 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl =
2159 IOleCommandTargetImpl_QueryInterface,
2160 IOleCommandTargetImpl_AddRef,
2161 IOleCommandTargetImpl_Release,
2162 IOleCommandTargetImpl_QueryStatus,
2163 IOleCommandTargetImpl_Exec
2166 typedef struct {
2167 IServiceProvider IServiceProvider_iface;
2168 LONG ref;
2169 } IServiceProviderImpl;
2171 static inline IServiceProviderImpl *impl_from_IServiceProvider(IServiceProvider *iface)
2173 return CONTAINING_RECORD(iface, IServiceProviderImpl, IServiceProvider_iface);
2176 typedef struct {
2177 IProfferService IProfferService_iface;
2178 LONG ref;
2179 } IProfferServiceImpl;
2181 static inline IProfferServiceImpl *impl_from_IProfferService(IProfferService *iface)
2183 return CONTAINING_RECORD(iface, IProfferServiceImpl, IProfferService_iface);
2187 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl;
2188 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl;
2190 static IServiceProvider* IServiceProviderImpl_Construct(void)
2192 IServiceProviderImpl *obj;
2194 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2195 obj->IServiceProvider_iface.lpVtbl = &IServiceProviderImpl_Vtbl;
2196 obj->ref = 1;
2198 return &obj->IServiceProvider_iface;
2201 static IProfferService* IProfferServiceImpl_Construct(void)
2203 IProfferServiceImpl *obj;
2205 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2206 obj->IProfferService_iface.lpVtbl = &IProfferServiceImpl_Vtbl;
2207 obj->ref = 1;
2209 return &obj->IProfferService_iface;
2212 static HRESULT WINAPI IServiceProviderImpl_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppvObj)
2214 IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
2216 if (IsEqualIID(riid, &IID_IUnknown) ||
2217 IsEqualIID(riid, &IID_IServiceProvider))
2219 *ppvObj = This;
2222 if(*ppvObj)
2224 IServiceProvider_AddRef(iface);
2225 /* native uses redefined IID_IServiceProvider symbol, so we can't compare pointers */
2226 if (IsEqualIID(riid, &IID_IServiceProvider))
2227 add_call(&trace_got, 1, iface, &IID_IServiceProvider, 0, 0, 0);
2228 return S_OK;
2231 return E_NOINTERFACE;
2234 static ULONG WINAPI IServiceProviderImpl_AddRef(IServiceProvider *iface)
2236 IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
2237 return InterlockedIncrement(&This->ref);
2240 static ULONG WINAPI IServiceProviderImpl_Release(IServiceProvider *iface)
2242 IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
2243 ULONG ref = InterlockedDecrement(&This->ref);
2245 if (!ref)
2247 HeapFree(GetProcessHeap(), 0, This);
2248 return 0;
2250 return ref;
2253 static HRESULT WINAPI IServiceProviderImpl_QueryService(
2254 IServiceProvider *iface, REFGUID service, REFIID riid, void **ppv)
2256 /* native uses redefined pointer for IID_IOleCommandTarget, not one from uuid.lib */
2257 if (IsEqualIID(riid, &IID_IOleCommandTarget))
2259 add_call(&trace_got, 2, iface, service, &IID_IOleCommandTarget, 0, 0);
2260 *ppv = IOleCommandTargetImpl_Construct();
2262 if (IsEqualIID(riid, &IID_IProfferService))
2264 if (IsEqualIID(service, &IID_IProfferService))
2265 add_call(&trace_got, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2266 *ppv = IProfferServiceImpl_Construct();
2268 return S_OK;
2271 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl =
2273 IServiceProviderImpl_QueryInterface,
2274 IServiceProviderImpl_AddRef,
2275 IServiceProviderImpl_Release,
2276 IServiceProviderImpl_QueryService
2279 static void test_IUnknown_QueryServiceExec(void)
2281 IServiceProvider *provider;
2282 static const GUID dummy_serviceid = { 0xdeadbeef };
2283 static const GUID dummy_groupid = { 0xbeefbeef };
2284 call_trace_t trace_expected;
2285 HRESULT hr;
2287 /* on <=W2K platforms same ordinal used for another export with different
2288 prototype, so skipping using this indirect condition */
2289 if (is_win2k_and_lower)
2291 win_skip("IUnknown_QueryServiceExec is not available\n");
2292 return;
2295 provider = IServiceProviderImpl_Construct();
2297 /* null source pointer */
2298 hr = pIUnknown_QueryServiceExec(NULL, &dummy_serviceid, &dummy_groupid, 0, 0, 0, 0);
2299 ok(hr == E_FAIL ||
2300 hr == E_NOTIMPL, /* win 8 */
2301 "got 0x%08x\n", hr);
2303 /* expected trace:
2304 IUnknown_QueryServiceExec( ptr1, serviceid, groupid, arg1, arg2, arg3, arg4);
2305 -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &prov );
2306 -> IServiceProvider_QueryService( prov, serviceid, &IID_IOleCommandTarget, &obj );
2307 -> IOleCommandTarget_Exec( obj, groupid, arg1, arg2, arg3, arg4 );
2309 init_call_trace(&trace_expected);
2311 add_call(&trace_expected, 1, provider, &IID_IServiceProvider, 0, 0, 0);
2312 add_call(&trace_expected, 2, provider, &dummy_serviceid, &IID_IOleCommandTarget, 0, 0);
2313 add_call(&trace_expected, 3, &dummy_groupid, (void*)0x1, (void*)0x2, (void*)0x3, (void*)0x4);
2315 init_call_trace(&trace_got);
2316 hr = pIUnknown_QueryServiceExec((IUnknown*)provider, &dummy_serviceid, &dummy_groupid, 0x1, 0x2, (void*)0x3, (void*)0x4);
2317 ok(hr == S_OK, "got 0x%08x\n", hr);
2319 ok_trace(&trace_expected, &trace_got);
2321 free_call_trace(&trace_expected);
2322 free_call_trace(&trace_got);
2324 IServiceProvider_Release(provider);
2328 static HRESULT WINAPI IProfferServiceImpl_QueryInterface(IProfferService *iface, REFIID riid, void **ppvObj)
2330 IProfferServiceImpl *This = impl_from_IProfferService(iface);
2332 if (IsEqualIID(riid, &IID_IUnknown) ||
2333 IsEqualIID(riid, &IID_IProfferService))
2335 *ppvObj = This;
2337 else if (IsEqualIID(riid, &IID_IServiceProvider))
2339 *ppvObj = IServiceProviderImpl_Construct();
2340 add_call(&trace_got, 1, iface, &IID_IServiceProvider, 0, 0, 0);
2341 return S_OK;
2344 if(*ppvObj)
2346 IProfferService_AddRef(iface);
2347 return S_OK;
2350 return E_NOINTERFACE;
2353 static ULONG WINAPI IProfferServiceImpl_AddRef(IProfferService *iface)
2355 IProfferServiceImpl *This = impl_from_IProfferService(iface);
2356 return InterlockedIncrement(&This->ref);
2359 static ULONG WINAPI IProfferServiceImpl_Release(IProfferService *iface)
2361 IProfferServiceImpl *This = impl_from_IProfferService(iface);
2362 ULONG ref = InterlockedDecrement(&This->ref);
2364 if (!ref)
2366 HeapFree(GetProcessHeap(), 0, This);
2367 return 0;
2369 return ref;
2372 static HRESULT WINAPI IProfferServiceImpl_ProfferService(IProfferService *iface,
2373 REFGUID service, IServiceProvider *pService, DWORD *pCookie)
2375 *pCookie = 0xdeadbeef;
2376 add_call(&trace_got, 3, service, pService, pCookie, 0, 0);
2377 return S_OK;
2380 static HRESULT WINAPI IProfferServiceImpl_RevokeService(IProfferService *iface, DWORD cookie)
2382 add_call(&trace_got, 4, (void*)(DWORD_PTR)cookie, 0, 0, 0, 0);
2383 return S_OK;
2386 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl =
2388 IProfferServiceImpl_QueryInterface,
2389 IProfferServiceImpl_AddRef,
2390 IProfferServiceImpl_Release,
2391 IProfferServiceImpl_ProfferService,
2392 IProfferServiceImpl_RevokeService
2395 static void test_IUnknown_ProfferService(void)
2397 IServiceProvider *provider;
2398 IProfferService *proff;
2399 static const GUID dummy_serviceid = { 0xdeadbeef };
2400 call_trace_t trace_expected;
2401 HRESULT hr;
2402 DWORD cookie;
2404 /* on <=W2K platforms same ordinal used for another export with different
2405 prototype, so skipping using this indirect condition */
2406 if (is_win2k_and_lower)
2408 win_skip("IUnknown_ProfferService is not available\n");
2409 return;
2412 provider = IServiceProviderImpl_Construct();
2413 proff = IProfferServiceImpl_Construct();
2415 /* null source pointer */
2416 hr = pIUnknown_ProfferService(NULL, &dummy_serviceid, 0, 0);
2417 ok(hr == E_FAIL ||
2418 hr == E_NOTIMPL, /* win 8 */
2419 "got 0x%08x\n", hr);
2421 /* expected trace:
2422 IUnknown_ProfferService( ptr1, serviceid, arg1, arg2);
2423 -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &provider );
2424 -> IServiceProvider_QueryService( provider, &IID_IProfferService, &IID_IProfferService, &proffer );
2426 if (service pointer not null):
2427 -> IProfferService_ProfferService( proffer, serviceid, arg1, arg2 );
2428 else
2429 -> IProfferService_RevokeService( proffer, *arg2 );
2431 init_call_trace(&trace_expected);
2433 add_call(&trace_expected, 1, proff, &IID_IServiceProvider, 0, 0, 0);
2434 add_call(&trace_expected, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2435 add_call(&trace_expected, 3, &dummy_serviceid, provider, &cookie, 0, 0);
2437 init_call_trace(&trace_got);
2438 cookie = 0;
2439 hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, provider, &cookie);
2440 ok(hr == S_OK, "got 0x%08x\n", hr);
2441 ok(cookie == 0xdeadbeef, "got %x\n", cookie);
2443 ok_trace(&trace_expected, &trace_got);
2444 free_call_trace(&trace_got);
2445 free_call_trace(&trace_expected);
2447 /* same with ::Revoke path */
2448 init_call_trace(&trace_expected);
2450 add_call(&trace_expected, 1, proff, &IID_IServiceProvider, 0, 0, 0);
2451 add_call(&trace_expected, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2452 add_call(&trace_expected, 4, (void*)(DWORD_PTR)cookie, 0, 0, 0, 0);
2454 init_call_trace(&trace_got);
2455 ok(cookie != 0, "got %x\n", cookie);
2456 hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, 0, &cookie);
2457 ok(hr == S_OK, "got 0x%08x\n", hr);
2458 ok(cookie == 0, "got %x\n", cookie);
2459 ok_trace(&trace_expected, &trace_got);
2460 free_call_trace(&trace_got);
2461 free_call_trace(&trace_expected);
2463 IServiceProvider_Release(provider);
2464 IProfferService_Release(proff);
2467 static void test_SHCreateWorkerWindowA(void)
2469 WNDCLASSA cliA;
2470 char classA[20];
2471 HWND hwnd;
2472 LONG_PTR ret;
2473 BOOL res;
2475 if (is_win2k_and_lower)
2477 win_skip("SHCreateWorkerWindowA not available\n");
2478 return;
2481 hwnd = pSHCreateWorkerWindowA(0, NULL, 0, 0, 0, 0);
2482 ok(hwnd != 0, "expected window\n");
2484 GetClassNameA(hwnd, classA, 20);
2485 ok(lstrcmpA(classA, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA);
2487 ret = GetWindowLongPtrA(hwnd, 0);
2488 ok(ret == 0, "got %ld\n", ret);
2490 /* class info */
2491 memset(&cliA, 0, sizeof(cliA));
2492 res = GetClassInfoA(GetModuleHandleA("shlwapi.dll"), "WorkerA", &cliA);
2493 ok(res, "failed to get class info\n");
2494 ok(cliA.style == 0, "got 0x%08x\n", cliA.style);
2495 ok(cliA.cbClsExtra == 0, "got %d\n", cliA.cbClsExtra);
2496 ok(cliA.cbWndExtra == sizeof(LONG_PTR), "got %d\n", cliA.cbWndExtra);
2497 ok(cliA.lpszMenuName == 0, "got %s\n", cliA.lpszMenuName);
2499 DestroyWindow(hwnd);
2501 /* set extra bytes */
2502 hwnd = pSHCreateWorkerWindowA(0, NULL, 0, 0, 0, 0xdeadbeef);
2503 ok(hwnd != 0, "expected window\n");
2505 GetClassNameA(hwnd, classA, 20);
2506 ok(lstrcmpA(classA, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA);
2508 ret = GetWindowLongPtrA(hwnd, 0);
2509 ok(ret == 0xdeadbeef, "got %ld\n", ret);
2511 /* test exstyle */
2512 ret = GetWindowLongA(hwnd, GWL_EXSTYLE);
2513 ok(ret == WS_EX_WINDOWEDGE ||
2514 ret == (WS_EX_WINDOWEDGE|WS_EX_LAYOUTRTL) /* systems with RTL locale */, "0x%08lx\n", ret);
2516 DestroyWindow(hwnd);
2518 hwnd = pSHCreateWorkerWindowA(0, NULL, WS_EX_TOOLWINDOW, 0, 0, 0);
2519 ret = GetWindowLongA(hwnd, GWL_EXSTYLE);
2520 ok(ret == (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW) ||
2521 ret == (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW|WS_EX_LAYOUTRTL) /* systems with RTL locale */, "0x%08lx\n", ret);
2522 DestroyWindow(hwnd);
2525 static HRESULT WINAPI SF_QueryInterface(IShellFolder *iface,
2526 REFIID riid, void **ppv)
2528 /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */
2529 ok(!IsEqualGUID(&IID_IShellFolder, riid),
2530 "Unexpected QI for IShellFolder\n");
2531 return E_NOINTERFACE;
2534 static ULONG WINAPI SF_AddRef(IShellFolder *iface)
2536 return 2;
2539 static ULONG WINAPI SF_Release(IShellFolder *iface)
2541 return 1;
2544 static HRESULT WINAPI SF_ParseDisplayName(IShellFolder *iface,
2545 HWND owner, LPBC reserved, LPOLESTR displayName, ULONG *eaten,
2546 LPITEMIDLIST *idl, ULONG *attr)
2548 ok(0, "Didn't expect ParseDisplayName\n");
2549 return E_NOTIMPL;
2552 static HRESULT WINAPI SF_EnumObjects(IShellFolder *iface,
2553 HWND owner, SHCONTF flags, IEnumIDList **enm)
2555 *enm = (IEnumIDList*)0xcafebabe;
2556 return S_OK;
2559 static HRESULT WINAPI SF_BindToObject(IShellFolder *iface,
2560 LPCITEMIDLIST idl, LPBC reserved, REFIID riid, void **obj)
2562 ok(0, "Didn't expect BindToObject\n");
2563 return E_NOTIMPL;
2566 static HRESULT WINAPI SF_BindToStorage(IShellFolder *iface,
2567 LPCITEMIDLIST idl, LPBC reserved, REFIID riid, void **obj)
2569 ok(0, "Didn't expect BindToStorage\n");
2570 return E_NOTIMPL;
2573 static HRESULT WINAPI SF_CompareIDs(IShellFolder *iface,
2574 LPARAM lparam, LPCITEMIDLIST idl1, LPCITEMIDLIST idl2)
2576 ok(0, "Didn't expect CompareIDs\n");
2577 return E_NOTIMPL;
2580 static HRESULT WINAPI SF_CreateViewObject(IShellFolder *iface,
2581 HWND owner, REFIID riid, void **out)
2583 ok(0, "Didn't expect CreateViewObject\n");
2584 return E_NOTIMPL;
2587 static HRESULT WINAPI SF_GetAttributesOf(IShellFolder *iface,
2588 UINT cidl, LPCITEMIDLIST *idl, SFGAOF *inOut)
2590 ok(0, "Didn't expect GetAttributesOf\n");
2591 return E_NOTIMPL;
2594 static HRESULT WINAPI SF_GetUIObjectOf(IShellFolder *iface,
2595 HWND owner, UINT cidl, LPCITEMIDLIST *idls, REFIID riid, UINT *inOut,
2596 void **out)
2598 ok(0, "Didn't expect GetUIObjectOf\n");
2599 return E_NOTIMPL;
2602 static HRESULT WINAPI SF_GetDisplayNameOf(IShellFolder *iface,
2603 LPCITEMIDLIST idl, SHGDNF flags, STRRET *name)
2605 ok(0, "Didn't expect GetDisplayNameOf\n");
2606 return E_NOTIMPL;
2609 static HRESULT WINAPI SF_SetNameOf(IShellFolder *iface,
2610 HWND hwnd, LPCITEMIDLIST idl, LPCOLESTR name, SHGDNF flags,
2611 LPITEMIDLIST *idlOut)
2613 ok(0, "Didn't expect SetNameOf\n");
2614 return E_NOTIMPL;
2617 static IShellFolderVtbl ShellFolderVtbl = {
2618 SF_QueryInterface,
2619 SF_AddRef,
2620 SF_Release,
2621 SF_ParseDisplayName,
2622 SF_EnumObjects,
2623 SF_BindToObject,
2624 SF_BindToStorage,
2625 SF_CompareIDs,
2626 SF_CreateViewObject,
2627 SF_GetAttributesOf,
2628 SF_GetUIObjectOf,
2629 SF_GetDisplayNameOf,
2630 SF_SetNameOf
2633 static IShellFolder ShellFolder = { &ShellFolderVtbl };
2635 static void test_SHIShellFolder_EnumObjects(void)
2637 IEnumIDList *enm;
2638 HRESULT hres;
2639 IShellFolder *folder;
2641 if(!pSHIShellFolder_EnumObjects || is_win2k_and_lower){
2642 win_skip("SHIShellFolder_EnumObjects not available\n");
2643 return;
2646 if(0){
2647 /* NULL object crashes on Windows */
2648 pSHIShellFolder_EnumObjects(NULL, NULL, 0, NULL);
2651 /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */
2652 enm = (IEnumIDList*)0xdeadbeef;
2653 hres = pSHIShellFolder_EnumObjects(&ShellFolder, NULL, 0, &enm);
2654 ok(hres == S_OK, "SHIShellFolder_EnumObjects failed: 0x%08x\n", hres);
2655 ok(enm == (IEnumIDList*)0xcafebabe, "Didn't get expected enumerator location, instead: %p\n", enm);
2657 /* SHIShellFolder_EnumObjects isn't strict about the IShellFolder object */
2658 hres = pSHGetDesktopFolder(&folder);
2659 ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
2661 enm = NULL;
2662 hres = pSHIShellFolder_EnumObjects(folder, NULL, 0, &enm);
2663 ok(hres == S_OK, "SHIShellFolder_EnumObjects failed: 0x%08x\n", hres);
2664 ok(enm != NULL, "Didn't get an enumerator\n");
2665 if(enm)
2666 IEnumIDList_Release(enm);
2668 IShellFolder_Release(folder);
2671 static BOOL write_inifile(LPCWSTR filename)
2673 DWORD written;
2674 HANDLE file;
2676 static const char data[] =
2677 "[TestApp]\r\n"
2678 "AKey=1\r\n"
2679 "AnotherKey=asdf\r\n";
2681 file = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
2682 if(file == INVALID_HANDLE_VALUE) {
2683 win_skip("failed to create ini file at %s\n", wine_dbgstr_w(filename));
2684 return FALSE;
2687 WriteFile(file, data, sizeof(data), &written, NULL);
2689 CloseHandle(file);
2691 return TRUE;
2694 #define verify_inifile(f, e) r_verify_inifile(__LINE__, f, e)
2695 static void r_verify_inifile(unsigned l, LPCWSTR filename, LPCSTR exp)
2697 HANDLE file;
2698 CHAR buf[1024];
2699 DWORD read;
2701 file = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
2703 if(file == INVALID_HANDLE_VALUE)
2704 return;
2706 ReadFile(file, buf, sizeof(buf) * sizeof(CHAR), &read, NULL);
2707 buf[read] = '\0';
2709 CloseHandle(file);
2711 ok_(__FILE__,l)(!strcmp(buf, exp), "Expected:\n%s\nGot:\n%s\n", exp,
2712 buf);
2715 static void test_SHGetIniString(void)
2717 DWORD ret;
2718 WCHAR out[64] = {0};
2720 static const WCHAR TestAppW[] = {'T','e','s','t','A','p','p',0};
2721 static const WCHAR AKeyW[] = {'A','K','e','y',0};
2722 static const WCHAR AnotherKeyW[] = {'A','n','o','t','h','e','r','K','e','y',0};
2723 static const WCHAR JunkKeyW[] = {'J','u','n','k','K','e','y',0};
2724 static const WCHAR testpathW[] = {'C',':','\\','t','e','s','t','.','i','n','i',0};
2725 WCHAR pathW[MAX_PATH];
2727 if(!pSHGetIniStringW || is_win2k_and_lower){
2728 win_skip("SHGetIniStringW is not available\n");
2729 return;
2732 lstrcpyW(pathW, testpathW);
2734 if (!write_inifile(pathW))
2735 return;
2737 if(0){
2738 /* these crash on Windows */
2739 pSHGetIniStringW(NULL, NULL, NULL, 0, NULL);
2740 pSHGetIniStringW(NULL, AKeyW, out, sizeof(out), pathW);
2741 pSHGetIniStringW(TestAppW, AKeyW, NULL, sizeof(out), pathW);
2744 ret = pSHGetIniStringW(TestAppW, AKeyW, out, 0, pathW);
2745 ok(ret == 0, "SHGetIniStringW should have given 0, instead: %d\n", ret);
2747 /* valid arguments */
2748 out[0] = 0;
2749 SetLastError(0xdeadbeef);
2750 ret = pSHGetIniStringW(TestAppW, NULL, out, sizeof(out), pathW);
2751 ok(ret == 4, "SHGetIniStringW should have given 4, instead: %d\n", ret);
2752 ok(!lstrcmpW(out, AKeyW), "Expected %s, got: %s, %d\n",
2753 wine_dbgstr_w(AKeyW), wine_dbgstr_w(out), GetLastError());
2755 ret = pSHGetIniStringW(TestAppW, AKeyW, out, sizeof(out), pathW);
2756 ok(ret == 1, "SHGetIniStringW should have given 1, instead: %d\n", ret);
2757 ok(!strcmp_wa(out, "1"), "Expected L\"1\", got: %s\n", wine_dbgstr_w(out));
2759 ret = pSHGetIniStringW(TestAppW, AnotherKeyW, out, sizeof(out), pathW);
2760 ok(ret == 4, "SHGetIniStringW should have given 4, instead: %d\n", ret);
2761 ok(!strcmp_wa(out, "asdf"), "Expected L\"asdf\", got: %s\n", wine_dbgstr_w(out));
2763 out[0] = 1;
2764 ret = pSHGetIniStringW(TestAppW, JunkKeyW, out, sizeof(out), pathW);
2765 ok(ret == 0, "SHGetIniStringW should have given 0, instead: %d\n", ret);
2766 ok(*out == 0, "Expected L\"\", got: %s\n", wine_dbgstr_w(out));
2768 DeleteFileW(pathW);
2771 static void test_SHSetIniString(void)
2773 BOOL ret;
2775 static const WCHAR TestAppW[] = {'T','e','s','t','A','p','p',0};
2776 static const WCHAR AnotherAppW[] = {'A','n','o','t','h','e','r','A','p','p',0};
2777 static const WCHAR TestIniW[] = {'C',':','\\','t','e','s','t','.','i','n','i',0};
2778 static const WCHAR AKeyW[] = {'A','K','e','y',0};
2779 static const WCHAR NewKeyW[] = {'N','e','w','K','e','y',0};
2780 static const WCHAR AValueW[] = {'A','V','a','l','u','e',0};
2782 if(!pSHSetIniStringW || is_win2k_and_lower){
2783 win_skip("SHSetIniStringW is not available\n");
2784 return;
2787 if (!write_inifile(TestIniW))
2788 return;
2790 ret = pSHSetIniStringW(TestAppW, AKeyW, AValueW, TestIniW);
2791 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2792 todo_wine /* wine sticks an extra \r\n at the end of the file */
2793 verify_inifile(TestIniW, "[TestApp]\r\nAKey=AValue\r\nAnotherKey=asdf\r\n");
2795 ret = pSHSetIniStringW(TestAppW, AKeyW, NULL, TestIniW);
2796 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2797 verify_inifile(TestIniW, "[TestApp]\r\nAnotherKey=asdf\r\n");
2799 ret = pSHSetIniStringW(AnotherAppW, NewKeyW, AValueW, TestIniW);
2800 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2801 verify_inifile(TestIniW, "[TestApp]\r\nAnotherKey=asdf\r\n[AnotherApp]\r\nNewKey=AValue\r\n");
2803 ret = pSHSetIniStringW(TestAppW, NULL, AValueW, TestIniW);
2804 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2805 verify_inifile(TestIniW, "[AnotherApp]\r\nNewKey=AValue\r\n");
2807 DeleteFileW(TestIniW);
2810 enum _shellkey_flags {
2811 SHKEY_Root_HKCU = 0x1,
2812 SHKEY_Root_HKLM = 0x2,
2813 SHKEY_Key_Explorer = 0x00,
2814 SHKEY_Key_Shell = 0x10,
2815 SHKEY_Key_ShellNoRoam = 0x20,
2816 SHKEY_Key_Classes = 0x30,
2817 SHKEY_Subkey_Default = 0x0000,
2818 SHKEY_Subkey_ResourceName = 0x1000,
2819 SHKEY_Subkey_Handlers = 0x2000,
2820 SHKEY_Subkey_Associations = 0x3000,
2821 SHKEY_Subkey_Volatile = 0x4000,
2822 SHKEY_Subkey_MUICache = 0x5000,
2823 SHKEY_Subkey_FileExts = 0x6000
2826 static void test_SHGetShellKey(void)
2828 static const WCHAR ShellFoldersW[] = { 'S','h','e','l','l',' ','F','o','l','d','e','r','s',0 };
2829 static const WCHAR WineTestW[] = { 'W','i','n','e','T','e','s','t',0 };
2831 void *pPathBuildRootW = GetProcAddress(hShlwapi, "PathBuildRootW");
2832 DWORD *alloc_data, data, size;
2833 HKEY hkey;
2834 HRESULT hres;
2836 if (!pSHGetShellKey)
2838 win_skip("SHGetShellKey(ordinal 491) isn't available\n");
2839 return;
2842 /* some win2k */
2843 if (pPathBuildRootW && pPathBuildRootW == pSHGetShellKey)
2845 win_skip("SHGetShellKey(ordinal 491) used for PathBuildRootW\n");
2846 return;
2849 if (is_win9x || is_win2k_and_lower)
2851 win_skip("Ordinal 491 used for another call, skipping SHGetShellKey tests\n");
2852 return;
2855 /* Vista+ limits SHKEY enumeration values */
2856 SetLastError(0xdeadbeef);
2857 hkey = pSHGetShellKey(SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2858 if (hkey)
2860 /* Tests not working on Vista+ */
2861 RegCloseKey(hkey);
2863 hkey = pSHGetShellKey(SHKEY_Root_HKLM|SHKEY_Key_Classes, NULL, FALSE);
2864 ok(hkey != NULL, "hkey = NULL\n");
2865 RegCloseKey(hkey);
2868 hkey = pSHGetShellKey(SHKEY_Root_HKCU|SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2869 ok(hkey != NULL, "hkey = NULL\n");
2870 RegCloseKey(hkey);
2872 hkey = pSHGetShellKey(SHKEY_Root_HKLM|SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2873 ok(hkey != NULL, "hkey = NULL\n");
2874 RegCloseKey(hkey);
2876 hkey = pSHGetShellKey(SHKEY_Root_HKLM, WineTestW, FALSE);
2877 ok(hkey == NULL, "hkey != NULL\n");
2879 hkey = pSHGetShellKey(SHKEY_Root_HKLM, NULL, FALSE);
2880 ok(hkey != NULL, "Can't open key\n");
2881 ok(SUCCEEDED(RegDeleteKeyW(hkey, WineTestW)), "Can't delete key\n");
2882 RegCloseKey(hkey);
2884 hkey = pSHGetShellKey(SHKEY_Root_HKLM, WineTestW, TRUE);
2885 if (!hkey && GetLastError() == ERROR_ACCESS_DENIED)
2887 skip("Not authorized to create keys\n");
2888 return;
2890 ok(hkey != NULL, "Can't create key\n");
2891 RegCloseKey(hkey);
2893 if (!pSKGetValueW || !pSKSetValueW || !pSKDeleteValueW || !pSKAllocValueW)
2895 win_skip("SKGetValueW, SKSetValueW, SKDeleteValueW or SKAllocValueW not available\n");
2896 return;
2899 size = sizeof(data);
2900 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
2901 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres);
2903 data = 1234;
2904 hres = pSKSetValueW(SHKEY_Root_HKLM, WineTestW, NULL, REG_DWORD, &data, sizeof(DWORD));
2905 ok(hres == S_OK, "hres = %x\n", hres);
2907 size = 1;
2908 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, NULL, &size);
2909 ok(hres == S_OK, "hres = %x\n", hres);
2910 ok(size == sizeof(DWORD), "size = %d\n", size);
2912 data = 0xdeadbeef;
2913 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
2914 ok(hres == S_OK, "hres = %x\n", hres);
2915 ok(size == sizeof(DWORD), "size = %d\n", size);
2916 ok(data == 1234, "data = %d\n", data);
2918 hres = pSKAllocValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, (void**)&alloc_data, &size);
2919 ok(hres == S_OK, "hres= %x\n", hres);
2920 ok(size == sizeof(DWORD), "size = %d\n", size);
2921 if (SUCCEEDED(hres))
2923 ok(*alloc_data == 1234, "*alloc_data = %d\n", *alloc_data);
2924 LocalFree(alloc_data);
2927 hres = pSKDeleteValueW(SHKEY_Root_HKLM, WineTestW, NULL);
2928 ok(hres == S_OK, "hres = %x\n", hres);
2930 hres = pSKDeleteValueW(SHKEY_Root_HKLM, WineTestW, NULL);
2931 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres);
2933 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
2934 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres);
2936 hkey = pSHGetShellKey(SHKEY_Root_HKLM, NULL, FALSE);
2937 ok(hkey != NULL, "Can't create key\n");
2938 ok(SUCCEEDED(RegDeleteKeyW(hkey, WineTestW)), "Can't delete key\n");
2939 RegCloseKey(hkey);
2942 static void init_pointers(void)
2944 #define MAKEFUNC(f, ord) (p##f = (void*)GetProcAddress(hShlwapi, (LPSTR)(ord)))
2945 MAKEFUNC(SHAllocShared, 7);
2946 MAKEFUNC(SHLockShared, 8);
2947 MAKEFUNC(SHUnlockShared, 9);
2948 MAKEFUNC(SHFreeShared, 10);
2949 MAKEFUNC(GetAcceptLanguagesA, 14);
2950 MAKEFUNC(SHSetWindowBits, 165);
2951 MAKEFUNC(SHSetParentHwnd, 167);
2952 MAKEFUNC(ConnectToConnectionPoint, 168);
2953 MAKEFUNC(SHSearchMapInt, 198);
2954 MAKEFUNC(SHCreateWorkerWindowA, 257);
2955 MAKEFUNC(GUIDFromStringA, 269);
2956 MAKEFUNC(SHPackDispParams, 282);
2957 MAKEFUNC(IConnectionPoint_InvokeWithCancel, 283);
2958 MAKEFUNC(IConnectionPoint_SimpleInvoke, 284);
2959 MAKEFUNC(SHGetIniStringW, 294);
2960 MAKEFUNC(SHSetIniStringW, 295);
2961 MAKEFUNC(SHFormatDateTimeA, 353);
2962 MAKEFUNC(SHFormatDateTimeW, 354);
2963 MAKEFUNC(SHIShellFolder_EnumObjects, 404);
2964 MAKEFUNC(SHGetObjectCompatFlags, 476);
2965 MAKEFUNC(IUnknown_QueryServiceExec, 484);
2966 MAKEFUNC(SHGetShellKey, 491);
2967 MAKEFUNC(SHPropertyBag_ReadLONG, 496);
2968 MAKEFUNC(IUnknown_ProfferService, 514);
2969 MAKEFUNC(SKGetValueW, 516);
2970 MAKEFUNC(SKSetValueW, 517);
2971 MAKEFUNC(SKDeleteValueW, 518);
2972 MAKEFUNC(SKAllocValueW, 519);
2973 #undef MAKEFUNC
2976 static void test_SHSetParentHwnd(void)
2978 HWND hwnd, hwnd2, ret;
2979 DWORD style;
2981 if (!pSHSetParentHwnd)
2983 win_skip("SHSetParentHwnd not available\n");
2984 return;
2987 hwnd = CreateWindowA("Button", "", WS_VISIBLE, 0, 0, 10, 10, NULL, NULL, NULL, NULL);
2988 ok(hwnd != NULL, "got %p\n", hwnd);
2990 hwnd2 = CreateWindowA("Button", "", WS_VISIBLE | WS_CHILD, 0, 0, 10, 10, hwnd, NULL, NULL, NULL);
2991 ok(hwnd2 != NULL, "got %p\n", hwnd2);
2993 /* null params */
2994 ret = pSHSetParentHwnd(NULL, NULL);
2995 ok(ret == NULL, "got %p\n", ret);
2997 /* set to no parent while already no parent present */
2998 ret = GetParent(hwnd);
2999 ok(ret == NULL, "got %p\n", ret);
3000 style = GetWindowLongA(hwnd, GWL_STYLE);
3001 ok((style & (WS_POPUP|WS_CHILD)) == 0, "got style 0x%08x\n", style);
3002 ret = pSHSetParentHwnd(hwnd, NULL);
3003 ok(ret == NULL, "got %p\n", ret);
3004 style = GetWindowLongA(hwnd, GWL_STYLE);
3005 ok((style & (WS_POPUP|WS_CHILD)) == 0, "got style 0x%08x\n", style);
3007 /* reset to null parent from not null */
3008 ret = GetParent(hwnd2);
3009 ok(ret == hwnd, "got %p\n", ret);
3010 style = GetWindowLongA(hwnd2, GWL_STYLE);
3011 ok((style & (WS_POPUP|WS_CHILD)) == WS_CHILD, "got style 0x%08x\n", style);
3012 ret = pSHSetParentHwnd(hwnd2, NULL);
3013 ok(ret == NULL, "got %p\n", ret);
3014 style = GetWindowLongA(hwnd2, GWL_STYLE);
3015 ok((style & (WS_POPUP|WS_CHILD)) == WS_POPUP, "got style 0x%08x\n", style);
3016 ret = GetParent(hwnd2);
3017 ok(ret == NULL, "got %p\n", ret);
3019 /* set parent back */
3020 style = GetWindowLongA(hwnd2, GWL_STYLE);
3021 SetWindowLongA(hwnd2, GWL_STYLE, style & ~(WS_CHILD|WS_POPUP));
3022 style = GetWindowLongA(hwnd2, GWL_STYLE);
3023 ok((style & (WS_CHILD|WS_POPUP)) == 0, "got 0x%08x\n", style);
3025 ret = pSHSetParentHwnd(hwnd2, hwnd);
3026 todo_wine ok(ret == NULL, "got %p\n", ret);
3028 style = GetWindowLongA(hwnd2, GWL_STYLE);
3029 ok((style & (WS_POPUP|WS_CHILD)) == WS_CHILD, "got style 0x%08x\n", style);
3030 ret = GetParent(hwnd2);
3031 ok(ret == hwnd, "got %p\n", ret);
3033 /* try to set same parent again */
3034 /* with WS_POPUP */
3035 style = GetWindowLongA(hwnd2, GWL_STYLE);
3036 SetWindowLongA(hwnd2, GWL_STYLE, style | WS_POPUP);
3037 ret = pSHSetParentHwnd(hwnd2, hwnd);
3038 todo_wine ok(ret == NULL, "got %p\n", ret);
3039 style = GetWindowLongA(hwnd2, GWL_STYLE);
3040 ok((style & (WS_CHILD|WS_POPUP)) == WS_CHILD, "got 0x%08x\n", style);
3041 ret = GetParent(hwnd2);
3042 ok(ret == hwnd, "got %p\n", ret);
3044 /* without WS_POPUP */
3045 style = GetWindowLongA(hwnd2, GWL_STYLE);
3046 SetWindowLongA(hwnd2, GWL_STYLE, style | ~WS_POPUP);
3047 ret = pSHSetParentHwnd(hwnd2, hwnd);
3048 todo_wine ok(ret == hwnd, "got %p\n", ret);
3049 style = GetWindowLongA(hwnd2, GWL_STYLE);
3050 ok((style & (WS_CHILD|WS_POPUP)) == WS_CHILD, "got 0x%08x\n", style);
3051 ret = GetParent(hwnd2);
3052 ok(ret == hwnd, "got %p\n", ret);
3054 DestroyWindow(hwnd);
3055 DestroyWindow(hwnd2);
3058 START_TEST(ordinal)
3060 hShlwapi = GetModuleHandleA("shlwapi.dll");
3061 is_win2k_and_lower = GetProcAddress(hShlwapi, "StrChrNW") == 0;
3062 is_win9x = GetProcAddress(hShlwapi, (LPSTR)99) == 0; /* StrCpyNXA */
3064 /* SHCreateStreamOnFileEx was introduced in shlwapi v6.0 */
3065 if(!GetProcAddress(hShlwapi, "SHCreateStreamOnFileEx")){
3066 win_skip("Too old shlwapi version\n");
3067 return;
3070 init_pointers();
3072 hmlang = LoadLibraryA("mlang.dll");
3073 pLcidToRfc1766A = (void *)GetProcAddress(hmlang, "LcidToRfc1766A");
3075 hshell32 = LoadLibraryA("shell32.dll");
3076 pSHGetDesktopFolder = (void *)GetProcAddress(hshell32, "SHGetDesktopFolder");
3078 test_GetAcceptLanguagesA();
3079 test_SHSearchMapInt();
3080 test_alloc_shared();
3081 test_fdsa();
3082 test_GetShellSecurityDescriptor();
3083 test_SHPackDispParams();
3084 test_IConnectionPoint();
3085 test_SHPropertyBag_ReadLONG();
3086 test_SHSetWindowBits();
3087 test_SHFormatDateTimeA();
3088 test_SHFormatDateTimeW();
3089 test_SHGetObjectCompatFlags();
3090 test_IUnknown_QueryServiceExec();
3091 test_IUnknown_ProfferService();
3092 test_SHCreateWorkerWindowA();
3093 test_SHIShellFolder_EnumObjects();
3094 test_SHGetIniString();
3095 test_SHSetIniString();
3096 test_SHGetShellKey();
3097 test_SHSetParentHwnd();
3099 FreeLibrary(hshell32);
3100 FreeLibrary(hmlang);