shlwapi: Remove unneeded UNALIGNED attributes.
[wine.git] / dlls / shlwapi / tests / ordinal.c
blob474c447686d0ea31b4bdb7ad40772817cb626f74
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;
40 static int (WINAPI *pSHSearchMapInt)(const int*,const int*,int,int);
41 static HRESULT (WINAPI *pGetAcceptLanguagesA)(LPSTR,LPDWORD);
43 static HANDLE (WINAPI *pSHAllocShared)(LPCVOID,DWORD,DWORD);
44 static LPVOID (WINAPI *pSHLockShared)(HANDLE,DWORD);
45 static BOOL (WINAPI *pSHUnlockShared)(LPVOID);
46 static BOOL (WINAPI *pSHFreeShared)(HANDLE,DWORD);
47 static HANDLE (WINAPI *pSHMapHandle)(HANDLE,DWORD,DWORD,DWORD,DWORD);
48 static HRESULT(WINAPIV *pSHPackDispParams)(DISPPARAMS*,VARIANTARG*,UINT,...);
49 static HRESULT(WINAPI *pIConnectionPoint_SimpleInvoke)(IConnectionPoint*,DISPID,DISPPARAMS*);
50 static HRESULT(WINAPI *pIConnectionPoint_InvokeWithCancel)(IConnectionPoint*,DISPID,DISPPARAMS*,DWORD,DWORD);
51 static HRESULT(WINAPI *pConnectToConnectionPoint)(IUnknown*,REFIID,BOOL,IUnknown*, LPDWORD,IConnectionPoint **);
52 static HRESULT(WINAPI *pSHPropertyBag_ReadLONG)(IPropertyBag *,LPCWSTR,LPLONG);
53 static LONG (WINAPI *pSHSetWindowBits)(HWND, INT, UINT, UINT);
54 static INT (WINAPI *pSHFormatDateTimeA)(const FILETIME*, DWORD*, LPSTR, UINT);
55 static INT (WINAPI *pSHFormatDateTimeW)(const FILETIME*, DWORD*, LPWSTR, UINT);
56 static DWORD (WINAPI *pSHGetObjectCompatFlags)(IUnknown*, const CLSID*);
57 static BOOL (WINAPI *pGUIDFromStringA)(LPSTR, CLSID *);
58 static HRESULT (WINAPI *pIUnknown_QueryServiceExec)(IUnknown*, REFIID, const GUID*, DWORD, DWORD, VARIANT*, VARIANT*);
59 static HRESULT (WINAPI *pIUnknown_ProfferService)(IUnknown*, REFGUID, IServiceProvider*, DWORD*);
60 static HWND (WINAPI *pSHCreateWorkerWindowA)(LONG, HWND, DWORD, DWORD, HMENU, LONG_PTR);
61 static HRESULT (WINAPI *pSHIShellFolder_EnumObjects)(LPSHELLFOLDER, HWND, SHCONTF, IEnumIDList**);
62 static DWORD (WINAPI *pSHGetIniStringW)(LPCWSTR, LPCWSTR, LPWSTR, DWORD, LPCWSTR);
63 static BOOL (WINAPI *pSHSetIniStringW)(LPCWSTR, LPCWSTR, LPCWSTR, LPCWSTR);
64 static HKEY (WINAPI *pSHGetShellKey)(DWORD, LPCWSTR, BOOL);
65 static HRESULT (WINAPI *pSKGetValueW)(DWORD, LPCWSTR, LPCWSTR, DWORD*, void*, DWORD*);
66 static HRESULT (WINAPI *pSKSetValueW)(DWORD, LPCWSTR, LPCWSTR, DWORD, void*, DWORD);
67 static HRESULT (WINAPI *pSKDeleteValueW)(DWORD, LPCWSTR, LPCWSTR);
68 static HRESULT (WINAPI *pSKAllocValueW)(DWORD, LPCWSTR, LPCWSTR, DWORD*, void**, DWORD*);
69 static HWND (WINAPI *pSHSetParentHwnd)(HWND, HWND);
70 static HRESULT (WINAPI *pIUnknown_GetClassID)(IUnknown*, CLSID*);
71 static HRESULT (WINAPI *pDllGetVersion)(DLLVERSIONINFO2*);
73 typedef struct SHELL_USER_SID {
74 SID_IDENTIFIER_AUTHORITY sidAuthority;
75 DWORD dwUserGroupID;
76 DWORD dwUserID;
77 } SHELL_USER_SID, *PSHELL_USER_SID;
78 typedef struct SHELL_USER_PERMISSION {
80 SHELL_USER_SID susID;
81 DWORD dwAccessType;
82 BOOL fInherit;
83 DWORD dwAccessMask;
84 DWORD dwInheritMask;
85 DWORD dwInheritAccessMask;
86 } SHELL_USER_PERMISSION, *PSHELL_USER_PERMISSION;
88 static SECURITY_DESCRIPTOR* (WINAPI *pGetShellSecurityDescriptor)(const SHELL_USER_PERMISSION**,int);
90 static const CHAR ie_international[] = {
91 'S','o','f','t','w','a','r','e','\\',
92 'M','i','c','r','o','s','o','f','t','\\',
93 'I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r','\\',
94 'I','n','t','e','r','n','a','t','i','o','n','a','l',0};
95 static const CHAR acceptlanguage[] = {
96 'A','c','c','e','p','t','L','a','n','g','u','a','g','e',0};
98 typedef struct {
99 int id;
100 const void *args[5];
101 } call_entry_t;
103 typedef struct {
104 call_entry_t *calls;
105 int count;
106 int alloc;
107 } call_trace_t;
109 static void init_call_trace(call_trace_t *ctrace)
111 ctrace->alloc = 10;
112 ctrace->count = 0;
113 ctrace->calls = HeapAlloc(GetProcessHeap(), 0, sizeof(call_entry_t) * ctrace->alloc);
116 static void free_call_trace(const call_trace_t *ctrace)
118 HeapFree(GetProcessHeap(), 0, ctrace->calls);
121 static void add_call(call_trace_t *ctrace, int id, const void *arg0,
122 const void *arg1, const void *arg2, const void *arg3, const void *arg4)
124 call_entry_t call;
126 call.id = id;
127 call.args[0] = arg0;
128 call.args[1] = arg1;
129 call.args[2] = arg2;
130 call.args[3] = arg3;
131 call.args[4] = arg4;
133 if (ctrace->count == ctrace->alloc)
135 ctrace->alloc *= 2;
136 ctrace->calls = HeapReAlloc(GetProcessHeap(),0, ctrace->calls, ctrace->alloc*sizeof(call_entry_t));
139 ctrace->calls[ctrace->count++] = call;
142 static void ok_trace_(call_trace_t *texpected, call_trace_t *tgot, int line)
144 if (texpected->count == tgot->count)
146 INT i;
147 /* compare */
148 for (i = 0; i < texpected->count; i++)
150 call_entry_t *expected = &texpected->calls[i];
151 call_entry_t *got = &tgot->calls[i];
152 INT j;
154 ok_(__FILE__, line)(expected->id == got->id, "got different ids %d: %d, %d\n", i+1, expected->id, got->id);
156 for (j = 0; j < 5; j++)
158 ok_(__FILE__, line)(expected->args[j] == got->args[j], "got different args[%d] for %d: %p, %p\n", j, i+1,
159 expected->args[j], got->args[j]);
163 else
164 ok_(__FILE__, line)(0, "traces length mismatch\n");
167 #define ok_trace(a, b) ok_trace_(a, b, __LINE__)
169 /* trace of actually made calls */
170 static call_trace_t trace_got;
172 static void test_GetAcceptLanguagesA(void)
174 static LPCSTR table[] = {"de,en-gb;q=0.7,en;q=0.3",
175 "de,en;q=0.3,en-gb;q=0.7", /* sorting is ignored */
176 "winetest", /* content is ignored */
177 "de-de,de;q=0.5",
178 "de",
179 NULL};
181 DWORD exactsize;
182 char original[512];
183 char language[32];
184 char buffer[64];
185 HKEY hroot = NULL;
186 LONG res_query = ERROR_SUCCESS;
187 LONG lres;
188 HRESULT hr;
189 DWORD maxlen = sizeof(buffer) - 2;
190 DWORD len;
191 LCID lcid;
192 LPCSTR entry;
193 INT i = 0;
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: %ld\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%lx\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 hr = LcidToRfc1766A(lcid, language, sizeof(language));
241 ok(hr == S_OK, "LcidToRfc1766A returned 0x%lx and %s\n", hr, language);
244 ok(!lstrcmpA(buffer, language),
245 "have '%s' (searching for '%s')\n", language, buffer);
247 if (lstrcmpA(buffer, language)) {
248 win_skip("no more ideas, how to build the default language '%s'\n", buffer);
249 goto restore_original;
252 trace("detected default: %s\n", language);
253 while ((entry = table[i])) {
255 exactsize = lstrlenA(entry);
257 lres = RegSetValueExA(hroot, acceptlanguage, 0, REG_SZ, (const BYTE *) entry, exactsize + 1);
258 ok(!lres, "got %ld for RegSetValueExA: %s\n", lres, entry);
260 /* len includes space for the terminating 0 before vista/w2k8 */
261 len = exactsize + 2;
262 memset(buffer, '#', maxlen);
263 buffer[maxlen] = 0;
264 hr = pGetAcceptLanguagesA( buffer, &len);
265 ok(((hr == E_INVALIDARG) && (len == 0)) ||
266 (SUCCEEDED(hr) &&
267 ((len == exactsize) || (len == exactsize+1)) &&
268 !lstrcmpA(buffer, entry)),
269 "+2_#%d: got 0x%lx with %ld and %s\n", i, hr, len, buffer);
271 len = exactsize + 1;
272 memset(buffer, '#', maxlen);
273 buffer[maxlen] = 0;
274 hr = pGetAcceptLanguagesA( buffer, &len);
275 ok(((hr == E_INVALIDARG) && (len == 0)) ||
276 (SUCCEEDED(hr) &&
277 ((len == exactsize) || (len == exactsize+1)) &&
278 !lstrcmpA(buffer, entry)),
279 "+1_#%d: got 0x%lx with %ld and %s\n", i, hr, len, buffer);
281 len = exactsize;
282 memset(buffer, '#', maxlen);
283 buffer[maxlen] = 0;
284 hr = pGetAcceptLanguagesA( buffer, &len);
286 /* There is no space for the string in the registry.
287 When the buffer is large enough, the default language is returned
289 When the buffer is too small for that fallback, win7_32 and w2k8_64
290 fail with E_NOT_SUFFICIENT_BUFFER, win8 fails with HRESULT_FROM_WIN32(ERROR_MORE_DATA),
291 other versions succeed and return a partial result while older os succeed
292 and overflow the buffer */
294 ok(((hr == E_INVALIDARG) && (len == 0)) ||
295 (((hr == S_OK) && !lstrcmpA(buffer, language) && (len == lstrlenA(language))) ||
296 ((hr == S_OK) && !memcmp(buffer, language, len)) ||
297 ((hr == E_NOT_SUFFICIENT_BUFFER) && !len) ||
298 ((hr == __HRESULT_FROM_WIN32(ERROR_MORE_DATA)) && len == exactsize)),
299 "==_#%d: got 0x%lx with %ld and %s\n", i, hr, len, buffer);
301 if (exactsize > 1) {
302 len = exactsize - 1;
303 memset(buffer, '#', maxlen);
304 buffer[maxlen] = 0;
305 hr = pGetAcceptLanguagesA( buffer, &len);
306 ok(((hr == E_INVALIDARG) && (len == 0)) ||
307 (((hr == S_OK) && !lstrcmpA(buffer, language) && (len == lstrlenA(language))) ||
308 ((hr == S_OK) && !memcmp(buffer, language, len)) ||
309 ((hr == E_NOT_SUFFICIENT_BUFFER) && !len) ||
310 ((hr == __HRESULT_FROM_WIN32(ERROR_MORE_DATA)) && len == exactsize - 1)),
311 "-1_#%d: got 0x%lx with %ld and %s\n", i, hr, len, buffer);
314 len = 1;
315 memset(buffer, '#', maxlen);
316 buffer[maxlen] = 0;
317 hr = pGetAcceptLanguagesA( buffer, &len);
318 ok(((hr == E_INVALIDARG) && (len == 0)) ||
319 (((hr == S_OK) && !lstrcmpA(buffer, language) && (len == lstrlenA(language))) ||
320 ((hr == S_OK) && !memcmp(buffer, language, len)) ||
321 ((hr == E_NOT_SUFFICIENT_BUFFER) && !len) ||
322 ((hr == __HRESULT_FROM_WIN32(ERROR_MORE_DATA)) && len == 1)),
323 "=1_#%d: got 0x%lx with %ld and %s\n", i, hr, len, buffer);
325 len = maxlen;
326 hr = pGetAcceptLanguagesA( NULL, &len);
328 /* w2k3 and below: E_FAIL and untouched len,
329 since w2k8: S_OK and needed size (excluding 0), win8 S_OK and size including 0. */
330 ok( ((hr == S_OK) && ((len == exactsize) || (len == exactsize + 1))) ||
331 ((hr == E_FAIL) && (len == maxlen)),
332 "NULL,max #%d: got 0x%lx with %ld and %s\n", i, hr, len, buffer);
334 i++;
337 /* without a value in the registry, a default language is returned */
338 RegDeleteValueA(hroot, acceptlanguage);
340 len = maxlen;
341 memset(buffer, '#', maxlen);
342 buffer[maxlen] = 0;
343 hr = pGetAcceptLanguagesA( buffer, &len);
344 ok( ((hr == S_OK) && (len == lstrlenA(language))),
345 "max: got 0x%lx with %ld and %s (expected S_OK with %d and '%s'\n",
346 hr, len, buffer, lstrlenA(language), language);
348 len = 2;
349 memset(buffer, '#', maxlen);
350 buffer[maxlen] = 0;
351 hr = pGetAcceptLanguagesA( buffer, &len);
352 ok( (((hr == S_OK) || (hr == E_INVALIDARG)) && !memcmp(buffer, language, len)) ||
353 ((hr == E_NOT_SUFFICIENT_BUFFER) && !len) ||
354 ((hr == __HRESULT_FROM_WIN32(ERROR_CANNOT_COPY)) && !len),
355 "=2: got 0x%lx with %ld and %s\n", hr, len, buffer);
357 len = 1;
358 memset(buffer, '#', maxlen);
359 buffer[maxlen] = 0;
360 hr = pGetAcceptLanguagesA( buffer, &len);
361 /* When the buffer is too small, win7_32 and w2k8_64 and above fail with
362 E_NOT_SUFFICIENT_BUFFER, win8 ERROR_CANNOT_COPY,
363 other versions succeed and return a partial 0 terminated result while other versions
364 fail with E_INVALIDARG and return a partial unterminated result */
365 ok( (((hr == S_OK) || (hr == E_INVALIDARG)) && !memcmp(buffer, language, len)) ||
366 ((hr == E_NOT_SUFFICIENT_BUFFER) && !len) ||
367 ((hr == __HRESULT_FROM_WIN32(ERROR_CANNOT_COPY)) && !len),
368 "=1: got 0x%lx with %ld and %s\n", hr, len, buffer);
370 len = 0;
371 memset(buffer, '#', maxlen);
372 buffer[maxlen] = 0;
373 hr = pGetAcceptLanguagesA( buffer, &len);
374 /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG, win8 ERROR_CANNOT_COPY */
375 ok((hr == E_FAIL) || (hr == E_INVALIDARG) || (hr == __HRESULT_FROM_WIN32(ERROR_CANNOT_COPY)),
376 "got 0x%lx\n", hr);
378 memset(buffer, '#', maxlen);
379 buffer[maxlen] = 0;
380 hr = pGetAcceptLanguagesA( buffer, NULL);
381 /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG */
382 ok((hr == E_FAIL) || (hr == E_INVALIDARG),
383 "got 0x%lx (expected E_FAIL or E_INVALIDARG)\n", hr);
386 hr = pGetAcceptLanguagesA( NULL, NULL);
387 /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG */
388 ok((hr == E_FAIL) || (hr == E_INVALIDARG),
389 "got 0x%lx (expected E_FAIL or E_INVALIDARG)\n", hr);
391 restore_original:
392 if (!res_query) {
393 len = lstrlenA(original);
394 lres = RegSetValueExA(hroot, acceptlanguage, 0, REG_SZ, (const BYTE *) original, len ? len + 1: 0);
395 ok(!lres, "RegSetValueEx(%s) failed: %ld\n", original, lres);
397 else
399 RegDeleteValueA(hroot, acceptlanguage);
401 RegCloseKey(hroot);
404 static void test_SHSearchMapInt(void)
406 int keys[8], values[8];
407 int i = 0;
409 if (!pSHSearchMapInt)
410 return;
412 memset(keys, 0, sizeof(keys));
413 memset(values, 0, sizeof(values));
414 keys[0] = 99; values[0] = 101;
416 /* NULL key/value lists crash native, so skip testing them */
418 /* 1 element */
419 i = pSHSearchMapInt(keys, values, 1, keys[0]);
420 ok(i == values[0], "Len 1, expected %d, got %d\n", values[0], i);
422 /* Key doesn't exist */
423 i = pSHSearchMapInt(keys, values, 1, 100);
424 ok(i == -1, "Len 1 - bad key, expected -1, got %d\n", i);
426 /* Len = 0 => not found */
427 i = pSHSearchMapInt(keys, values, 0, keys[0]);
428 ok(i == -1, "Len 1 - passed len 0, expected -1, got %d\n", i);
430 /* 2 elements, len = 1 */
431 keys[1] = 98; values[1] = 102;
432 i = pSHSearchMapInt(keys, values, 1, keys[1]);
433 ok(i == -1, "Len 1 - array len 2, expected -1, got %d\n", i);
435 /* 2 elements, len = 2 */
436 i = pSHSearchMapInt(keys, values, 2, keys[1]);
437 ok(i == values[1], "Len 2, expected %d, got %d\n", values[1], i);
439 /* Searches forward */
440 keys[2] = 99; values[2] = 103;
441 i = pSHSearchMapInt(keys, values, 3, keys[0]);
442 ok(i == values[0], "Len 3, expected %d, got %d\n", values[0], i);
445 struct shared_struct
447 DWORD value;
448 HANDLE handle;
451 static void test_alloc_shared(int argc, char **argv)
453 char cmdline[MAX_PATH];
454 PROCESS_INFORMATION pi;
455 STARTUPINFOA si = { 0 };
456 DWORD procid;
457 HANDLE hmem, hmem2 = 0;
458 struct shared_struct val, *p;
459 BOOL ret;
461 procid=GetCurrentProcessId();
462 hmem=pSHAllocShared(NULL,10,procid);
463 ok(hmem!=NULL,"SHAllocShared(NULL...) failed: %lu\n", GetLastError());
464 ret = pSHFreeShared(hmem, procid);
465 ok( ret, "SHFreeShared failed: %lu\n", GetLastError());
467 val.value = 0x12345678;
468 val.handle = 0;
469 hmem = pSHAllocShared(&val, sizeof(val), procid);
470 ok(hmem!=NULL,"SHAllocShared(NULL...) failed: %lu\n", GetLastError());
472 p=pSHLockShared(hmem,procid);
473 ok(p!=NULL,"SHLockShared failed: %lu\n", GetLastError());
474 if (p!=NULL)
475 ok(p->value == 0x12345678, "Wrong value in shared memory: %ld instead of %d\n", p->value, 0x12345678);
476 ret = pSHUnlockShared(p);
477 ok( ret, "SHUnlockShared failed: %lu\n", GetLastError());
479 sprintf(cmdline, "%s %s %ld %p", argv[0], argv[1], procid, hmem);
480 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
481 ok(ret, "could not create child process error: %lu\n", GetLastError());
482 if (ret)
484 wait_child_process(pi.hProcess);
485 CloseHandle(pi.hThread);
486 CloseHandle(pi.hProcess);
488 p = pSHLockShared(hmem, procid);
489 ok(p != NULL,"SHLockShared failed: %lu\n", GetLastError());
490 if (p != NULL && p->value != 0x12345678)
492 ok(p->value == 0x12345679, "Wrong value in shared memory: %ld instead of %d\n", p->value, 0x12345679);
493 hmem2 = p->handle;
494 ok(hmem2 != NULL, "Expected handle in shared memory\n");
496 ret = pSHUnlockShared(p);
497 ok(ret, "SHUnlockShared failed: %lu\n", GetLastError());
500 ret = pSHFreeShared(hmem, procid);
501 ok( ret, "SHFreeShared failed: %lu\n", GetLastError());
503 if (hmem2)
505 p = pSHLockShared(hmem2, procid);
506 ok(p != NULL,"SHLockShared failed: %lu\n", GetLastError());
507 if (p != NULL)
508 ok(p->value == 0xDEADBEEF, "Wrong value in shared memory: %ld instead of %d\n", p->value, 0xDEADBEEF);
509 ret = pSHUnlockShared(p);
510 ok(ret, "SHUnlockShared failed: %lu\n", GetLastError());
512 ret = pSHFreeShared(hmem2, procid);
513 ok(ret, "SHFreeShared failed: %lu\n", GetLastError());
516 SetLastError(0xdeadbeef);
517 ret = pSHFreeShared(NULL, procid);
518 ok(ret, "SHFreeShared failed: %lu\n", GetLastError());
519 ok(GetLastError() == 0xdeadbeef, "last error should not have changed, got %lu\n", GetLastError());
522 static void test_alloc_shared_remote(DWORD procid, HANDLE hmem)
524 struct shared_struct val, *p;
525 HANDLE hmem2;
526 BOOL ret;
528 /* test directly accessing shared memory of a remote process */
529 p = pSHLockShared(hmem, procid);
530 ok(p != NULL || broken(p == NULL) /* Windows 7/8 */, "SHLockShared failed: %lu\n", GetLastError());
531 if (p == NULL)
533 win_skip("Subprocess failed to modify shared memory, skipping test\n");
534 return;
537 ok(p->value == 0x12345678, "Wrong value in shared memory: %ld instead of %d\n", p->value, 0x12345678);
538 p->value++;
540 val.value = 0xDEADBEEF;
541 val.handle = 0;
542 p->handle = pSHAllocShared(&val, sizeof(val), procid);
543 ok(p->handle != NULL, "SHAllocShared failed: %lu\n", GetLastError());
545 ret = pSHUnlockShared(p);
546 ok(ret, "SHUnlockShared failed: %lu\n", GetLastError());
548 /* test SHMapHandle */
549 SetLastError(0xdeadbeef);
550 hmem2 = pSHMapHandle(NULL, procid, GetCurrentProcessId(), 0, 0);
551 ok(hmem2 == NULL, "expected NULL, got new handle\n");
552 ok(GetLastError() == 0xdeadbeef, "last error should not have changed, got %lu\n", GetLastError());
554 hmem2 = pSHMapHandle(hmem, procid, GetCurrentProcessId(), 0, 0);
556 /* It seems like Windows Vista/2008 uses a different internal implementation
557 * for shared memory, and calling SHMapHandle fails. */
558 ok(hmem2 != NULL || broken(hmem2 == NULL),
559 "SHMapHandle failed: %lu\n", GetLastError());
560 if (hmem2 == NULL)
562 win_skip("Subprocess failed to map shared memory, skipping test\n");
563 return;
566 p = pSHLockShared(hmem2, GetCurrentProcessId());
567 ok(p != NULL, "SHLockShared failed: %lu\n", GetLastError());
569 if (p != NULL)
570 ok(p->value == 0x12345679, "Wrong value in shared memory: %ld instead of %d\n", p->value, 0x12345679);
572 ret = pSHUnlockShared(p);
573 ok(ret, "SHUnlockShared failed: %lu\n", GetLastError());
575 ret = pSHFreeShared(hmem2, GetCurrentProcessId());
576 ok(ret, "SHFreeShared failed: %lu\n", GetLastError());
579 static void test_fdsa(void)
581 typedef struct
583 DWORD num_items; /* Number of elements inserted */
584 void *mem; /* Ptr to array */
585 DWORD blocks_alloced; /* Number of elements allocated */
586 BYTE inc; /* Number of elements to grow by when we need to expand */
587 BYTE block_size; /* Size in bytes of an element */
588 BYTE flags; /* Flags */
589 } FDSA_info;
591 BOOL (WINAPI *pFDSA_Initialize)(DWORD block_size, DWORD inc, FDSA_info *info, void *mem,
592 DWORD init_blocks);
593 BOOL (WINAPI *pFDSA_Destroy)(FDSA_info *info);
594 DWORD (WINAPI *pFDSA_InsertItem)(FDSA_info *info, DWORD where, const void *block);
595 BOOL (WINAPI *pFDSA_DeleteItem)(FDSA_info *info, DWORD where);
597 FDSA_info info;
598 int block_size = 10, init_blocks = 4, inc = 2;
599 DWORD ret;
600 char *mem;
602 pFDSA_Initialize = (void *)GetProcAddress(hShlwapi, (LPSTR)208);
603 pFDSA_Destroy = (void *)GetProcAddress(hShlwapi, (LPSTR)209);
604 pFDSA_InsertItem = (void *)GetProcAddress(hShlwapi, (LPSTR)210);
605 pFDSA_DeleteItem = (void *)GetProcAddress(hShlwapi, (LPSTR)211);
607 mem = HeapAlloc(GetProcessHeap(), 0, block_size * init_blocks);
608 memset(&info, 0, sizeof(info));
610 ok(pFDSA_Initialize(block_size, inc, &info, mem, init_blocks), "FDSA_Initialize rets FALSE\n");
611 ok(info.num_items == 0, "num_items = %ld\n", info.num_items);
612 ok(info.mem == mem, "mem = %p\n", info.mem);
613 ok(info.blocks_alloced == init_blocks, "blocks_alloced = %ld\n", info.blocks_alloced);
614 ok(info.inc == inc, "inc = %d\n", info.inc);
615 ok(info.block_size == block_size, "block_size = %d\n", info.block_size);
616 ok(info.flags == 0, "flags = %d\n", info.flags);
618 ret = pFDSA_InsertItem(&info, 1234, "1234567890");
619 ok(ret == 0, "ret = %ld\n", ret);
620 ok(info.num_items == 1, "num_items = %ld\n", info.num_items);
621 ok(info.mem == mem, "mem = %p\n", info.mem);
622 ok(info.blocks_alloced == init_blocks, "blocks_alloced = %ld\n", info.blocks_alloced);
623 ok(info.inc == inc, "inc = %d\n", info.inc);
624 ok(info.block_size == block_size, "block_size = %d\n", info.block_size);
625 ok(info.flags == 0, "flags = %d\n", info.flags);
627 ret = pFDSA_InsertItem(&info, 1234, "abcdefghij");
628 ok(ret == 1, "ret = %ld\n", ret);
630 ret = pFDSA_InsertItem(&info, 1, "klmnopqrst");
631 ok(ret == 1, "ret = %ld\n", ret);
633 ret = pFDSA_InsertItem(&info, 0, "uvwxyzABCD");
634 ok(ret == 0, "ret = %ld\n", ret);
635 ok(info.mem == mem, "mem = %p\n", info.mem);
636 ok(info.flags == 0, "flags = %d\n", info.flags);
638 /* This next InsertItem will cause shlwapi to allocate its own mem buffer */
639 ret = pFDSA_InsertItem(&info, 0, "EFGHIJKLMN");
640 ok(ret == 0, "ret = %ld\n", ret);
641 ok(info.mem != mem, "mem = %p\n", info.mem);
642 ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %ld\n", info.blocks_alloced);
643 ok(info.flags == 0x1, "flags = %d\n", info.flags);
645 ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCD1234567890klmnopqrstabcdefghij", 50), "mem %s\n", (char*)info.mem);
647 ok(pFDSA_DeleteItem(&info, 2), "rets FALSE\n");
648 ok(info.mem != mem, "mem = %p\n", info.mem);
649 ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %ld\n", info.blocks_alloced);
650 ok(info.flags == 0x1, "flags = %d\n", info.flags);
652 ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCDklmnopqrstabcdefghij", 40), "mem %s\n", (char*)info.mem);
654 ok(pFDSA_DeleteItem(&info, 3), "rets FALSE\n");
655 ok(info.mem != mem, "mem = %p\n", info.mem);
656 ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %ld\n", info.blocks_alloced);
657 ok(info.flags == 0x1, "flags = %d\n", info.flags);
659 ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCDklmnopqrst", 30), "mem %s\n", (char*)info.mem);
661 ok(!pFDSA_DeleteItem(&info, 4), "does not ret FALSE\n");
663 /* As shlwapi has allocated memory internally, Destroy will ret FALSE */
664 ok(!pFDSA_Destroy(&info), "FDSA_Destroy does not ret FALSE\n");
667 /* When Initialize is called with inc = 0, set it to 1 */
668 ok(pFDSA_Initialize(block_size, 0, &info, mem, init_blocks), "FDSA_Initialize rets FALSE\n");
669 ok(info.inc == 1, "inc = %d\n", info.inc);
671 /* This time, because shlwapi hasn't had to allocate memory
672 internally, Destroy rets non-zero */
673 ok(pFDSA_Destroy(&info), "FDSA_Destroy rets FALSE\n");
676 HeapFree(GetProcessHeap(), 0, mem);
679 static void test_GetShellSecurityDescriptor(void)
681 static const SHELL_USER_PERMISSION supCurrentUserFull = {
682 { {SECURITY_NULL_SID_AUTHORITY}, 0, 0 },
683 ACCESS_ALLOWED_ACE_TYPE, FALSE,
684 GENERIC_ALL, 0, 0 };
685 #define MY_INHERITANCE 0xBE /* invalid value to proof behavior */
686 static const SHELL_USER_PERMISSION supEveryoneDenied = {
687 { {SECURITY_WORLD_SID_AUTHORITY}, SECURITY_WORLD_RID, 0 },
688 ACCESS_DENIED_ACE_TYPE, TRUE,
689 GENERIC_WRITE, MY_INHERITANCE | 0xDEADBA00, GENERIC_READ };
690 const SHELL_USER_PERMISSION* rgsup[2] = {
691 &supCurrentUserFull, &supEveryoneDenied,
693 SECURITY_DESCRIPTOR* psd;
695 if(!pGetShellSecurityDescriptor) /* vista and later */
697 win_skip("GetShellSecurityDescriptor not available\n");
698 return;
701 psd = pGetShellSecurityDescriptor(NULL, 2);
702 ok(psd==NULL, "GetShellSecurityDescriptor should fail\n");
703 psd = pGetShellSecurityDescriptor(rgsup, 0);
704 ok(psd==NULL, "GetShellSecurityDescriptor should fail, got %p\n", psd);
706 SetLastError(0xdeadbeef);
707 psd = pGetShellSecurityDescriptor(rgsup, 2);
708 ok(psd!=NULL, "GetShellSecurityDescriptor failed\n");
709 if (psd!=NULL)
711 BOOL bHasDacl = FALSE, bDefaulted, ret;
712 PACL pAcl;
713 DWORD dwRev;
714 SECURITY_DESCRIPTOR_CONTROL control;
716 ok(IsValidSecurityDescriptor(psd), "returned value is not valid SD\n");
718 ret = GetSecurityDescriptorControl(psd, &control, &dwRev);
719 ok(ret, "GetSecurityDescriptorControl failed with error %lu\n", GetLastError());
720 ok(0 == (control & SE_SELF_RELATIVE), "SD should be absolute\n");
722 ret = GetSecurityDescriptorDacl(psd, &bHasDacl, &pAcl, &bDefaulted);
723 ok(ret, "GetSecurityDescriptorDacl failed with error %lu\n", GetLastError());
725 ok(bHasDacl, "SD has no DACL\n");
726 if (bHasDacl)
728 ok(!bDefaulted, "DACL should not be defaulted\n");
730 ok(pAcl != NULL, "NULL DACL!\n");
731 if (pAcl != NULL)
733 ACL_SIZE_INFORMATION asiSize;
735 ok(IsValidAcl(pAcl), "DACL is not valid\n");
737 ret = GetAclInformation(pAcl, &asiSize, sizeof(asiSize), AclSizeInformation);
738 ok(ret, "GetAclInformation failed with error %lu\n", GetLastError());
740 ok(asiSize.AceCount == 3, "Incorrect number of ACEs: %ld entries\n", asiSize.AceCount);
741 if (asiSize.AceCount == 3)
743 ACCESS_ALLOWED_ACE *paaa; /* will use for DENIED too */
745 ret = GetAce(pAcl, 0, (LPVOID*)&paaa);
746 ok(ret, "GetAce failed with error %lu\n", GetLastError());
747 ok(paaa->Header.AceType == ACCESS_ALLOWED_ACE_TYPE,
748 "Invalid ACE type %d\n", paaa->Header.AceType);
749 ok(paaa->Header.AceFlags == 0, "Invalid ACE flags %x\n", paaa->Header.AceFlags);
750 ok(paaa->Mask == GENERIC_ALL, "Invalid ACE mask %lx\n", paaa->Mask);
752 ret = GetAce(pAcl, 1, (LPVOID*)&paaa);
753 ok(ret, "GetAce failed with error %lu\n", GetLastError());
754 ok(paaa->Header.AceType == ACCESS_DENIED_ACE_TYPE,
755 "Invalid ACE type %d\n", paaa->Header.AceType);
756 /* first one of two ACEs generated from inheritable entry - without inheritance */
757 ok(paaa->Header.AceFlags == 0, "Invalid ACE flags %x\n", paaa->Header.AceFlags);
758 ok(paaa->Mask == GENERIC_WRITE, "Invalid ACE mask %lx\n", paaa->Mask);
760 ret = GetAce(pAcl, 2, (LPVOID*)&paaa);
761 ok(ret, "GetAce failed with error %lu\n", GetLastError());
762 ok(paaa->Header.AceType == ACCESS_DENIED_ACE_TYPE,
763 "Invalid ACE type %d\n", paaa->Header.AceType);
764 /* second ACE - with inheritance */
765 ok(paaa->Header.AceFlags == MY_INHERITANCE,
766 "Invalid ACE flags %x\n", paaa->Header.AceFlags);
767 ok(paaa->Mask == GENERIC_READ, "Invalid ACE mask %lx\n", paaa->Mask);
772 LocalFree(psd);
776 static void test_SHPackDispParams(void)
778 DISPPARAMS params;
779 VARIANT vars[10];
780 HRESULT hres;
782 memset(&params, 0xc0, sizeof(params));
783 memset(vars, 0xc0, sizeof(vars));
784 hres = pSHPackDispParams(&params, vars, 1, VT_I4, 0xdeadbeef);
785 ok(hres == S_OK, "SHPackDispParams failed: %08lx\n", hres);
786 ok(params.cArgs == 1, "params.cArgs = %d\n", params.cArgs);
787 ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
788 ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
789 ok(params.rgvarg == vars, "params.rgvarg = %p\n", params.rgvarg);
790 ok(V_VT(vars) == VT_I4, "V_VT(var) = %d\n", V_VT(vars));
791 ok(V_I4(vars) == 0xdeadbeef, "failed %lx\n", V_I4(vars));
793 memset(&params, 0xc0, sizeof(params));
794 hres = pSHPackDispParams(&params, NULL, 0, 0);
795 ok(hres == S_OK, "SHPackDispParams failed: %08lx\n", hres);
796 ok(params.cArgs == 0, "params.cArgs = %d\n", params.cArgs);
797 ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
798 ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
799 ok(params.rgvarg == NULL, "params.rgvarg = %p\n", params.rgvarg);
801 memset(vars, 0xc0, sizeof(vars));
802 memset(&params, 0xc0, sizeof(params));
803 hres = pSHPackDispParams(&params, vars, 4, VT_BSTR, (void*)0xdeadbeef, VT_EMPTY, 10,
804 VT_I4, 100, VT_DISPATCH, (void*)0xdeadbeef);
805 ok(hres == S_OK, "SHPackDispParams failed: %08lx\n", hres);
806 ok(params.cArgs == 4, "params.cArgs = %d\n", params.cArgs);
807 ok(params.cNamedArgs == 0, "params.cNamedArgs = %d\n", params.cArgs);
808 ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs);
809 ok(params.rgvarg == vars, "params.rgvarg = %p\n", params.rgvarg);
810 ok(V_VT(vars) == VT_DISPATCH, "V_VT(vars[0]) = %x\n", V_VT(vars));
811 ok(V_I4(vars) == 0xdeadbeef, "V_I4(vars[0]) = %lx\n", V_I4(vars));
812 ok(V_VT(vars+1) == VT_I4, "V_VT(vars[1]) = %d\n", V_VT(vars+1));
813 ok(V_I4(vars+1) == 100, "V_I4(vars[1]) = %lx\n", V_I4(vars+1));
814 ok(V_VT(vars+2) == VT_I4, "V_VT(vars[2]) = %d\n", V_VT(vars+2));
815 ok(V_I4(vars+2) == 10, "V_I4(vars[2]) = %lx\n", V_I4(vars+2));
816 ok(V_VT(vars+3) == VT_BSTR, "V_VT(vars[3]) = %d\n", V_VT(vars+3));
817 ok(V_BSTR(vars+3) == (void*)0xdeadbeef, "V_BSTR(vars[3]) = %p\n", V_BSTR(vars+3));
820 typedef struct _disp
822 IDispatch IDispatch_iface;
823 LONG refCount;
824 } Disp;
826 static inline Disp *impl_from_IDispatch(IDispatch *iface)
828 return CONTAINING_RECORD(iface, Disp, IDispatch_iface);
831 typedef struct _contain
833 IConnectionPointContainer IConnectionPointContainer_iface;
834 LONG refCount;
836 UINT ptCount;
837 IConnectionPoint **pt;
838 } Contain;
840 static inline Contain *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
842 return CONTAINING_RECORD(iface, Contain, IConnectionPointContainer_iface);
845 typedef struct _cntptn
847 IConnectionPoint IConnectionPoint_iface;
848 LONG refCount;
850 Contain *container;
851 GUID id;
852 UINT sinkCount;
853 IUnknown **sink;
854 } ConPt;
856 static inline ConPt *impl_from_IConnectionPoint(IConnectionPoint *iface)
858 return CONTAINING_RECORD(iface, ConPt, IConnectionPoint_iface);
861 typedef struct _enum
863 IEnumConnections IEnumConnections_iface;
864 LONG refCount;
866 UINT idx;
867 ConPt *pt;
868 } EnumCon;
870 static inline EnumCon *impl_from_IEnumConnections(IEnumConnections *iface)
872 return CONTAINING_RECORD(iface, EnumCon, IEnumConnections_iface);
875 typedef struct _enumpt
877 IEnumConnectionPoints IEnumConnectionPoints_iface;
878 LONG refCount;
880 int idx;
881 Contain *container;
882 } EnumPt;
884 static inline EnumPt *impl_from_IEnumConnectionPoints(IEnumConnectionPoints *iface)
886 return CONTAINING_RECORD(iface, EnumPt, IEnumConnectionPoints_iface);
890 static HRESULT WINAPI Disp_QueryInterface(
891 IDispatch* This,
892 REFIID riid,
893 void **ppvObject)
895 *ppvObject = NULL;
897 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDispatch))
899 *ppvObject = This;
902 if (*ppvObject)
904 IDispatch_AddRef(This);
905 return S_OK;
908 trace("no interface\n");
909 return E_NOINTERFACE;
912 static ULONG WINAPI Disp_AddRef(IDispatch* This)
914 Disp *iface = impl_from_IDispatch(This);
915 return InterlockedIncrement(&iface->refCount);
918 static ULONG WINAPI Disp_Release(IDispatch* This)
920 Disp *iface = impl_from_IDispatch(This);
921 ULONG ret;
923 ret = InterlockedDecrement(&iface->refCount);
924 if (ret == 0)
925 HeapFree(GetProcessHeap(),0,This);
926 return ret;
929 static HRESULT WINAPI Disp_GetTypeInfoCount(
930 IDispatch* This,
931 UINT *pctinfo)
933 return ERROR_SUCCESS;
936 static HRESULT WINAPI Disp_GetTypeInfo(
937 IDispatch* This,
938 UINT iTInfo,
939 LCID lcid,
940 ITypeInfo **ppTInfo)
942 return ERROR_SUCCESS;
945 static HRESULT WINAPI Disp_GetIDsOfNames(
946 IDispatch* This,
947 REFIID riid,
948 LPOLESTR *rgszNames,
949 UINT cNames,
950 LCID lcid,
951 DISPID *rgDispId)
953 return ERROR_SUCCESS;
956 static HRESULT WINAPI Disp_Invoke(
957 IDispatch* This,
958 DISPID dispIdMember,
959 REFIID riid,
960 LCID lcid,
961 WORD wFlags,
962 DISPPARAMS *pDispParams,
963 VARIANT *pVarResult,
964 EXCEPINFO *pExcepInfo,
965 UINT *puArgErr)
967 trace("%p %lx %s %lx %x %p %p %p %p\n", This, dispIdMember, wine_dbgstr_guid(riid), lcid, wFlags,
968 pDispParams, pVarResult, pExcepInfo, puArgErr);
970 ok(dispIdMember == 0xa0 || dispIdMember == 0xa1, "Unknown dispIdMember\n");
971 ok(pDispParams != NULL, "Invoked with NULL pDispParams\n");
972 ok(wFlags == DISPATCH_METHOD, "Wrong flags %x\n",wFlags);
973 ok(lcid == 0,"Wrong lcid %lx\n",lcid);
974 if (dispIdMember == 0xa0)
976 ok(pDispParams->cArgs == 0, "params.cArgs = %d\n", pDispParams->cArgs);
977 ok(pDispParams->cNamedArgs == 0, "params.cNamedArgs = %d\n", pDispParams->cArgs);
978 ok(pDispParams->rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", pDispParams->rgdispidNamedArgs);
979 ok(pDispParams->rgvarg == NULL, "params.rgvarg = %p\n", pDispParams->rgvarg);
981 else if (dispIdMember == 0xa1)
983 ok(pDispParams->cArgs == 2, "params.cArgs = %d\n", pDispParams->cArgs);
984 ok(pDispParams->cNamedArgs == 0, "params.cNamedArgs = %d\n", pDispParams->cArgs);
985 ok(pDispParams->rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", pDispParams->rgdispidNamedArgs);
986 ok(V_VT(pDispParams->rgvarg) == VT_BSTR, "V_VT(var) = %d\n", V_VT(pDispParams->rgvarg));
987 ok(V_I4(pDispParams->rgvarg) == 0xdeadcafe , "failed %p\n", V_BSTR(pDispParams->rgvarg));
988 ok(V_VT(pDispParams->rgvarg+1) == VT_I4, "V_VT(var) = %d\n", V_VT(pDispParams->rgvarg+1));
989 ok(V_I4(pDispParams->rgvarg+1) == 0xdeadbeef, "failed %lx\n", V_I4(pDispParams->rgvarg+1));
992 return ERROR_SUCCESS;
995 static const IDispatchVtbl disp_vtbl = {
996 Disp_QueryInterface,
997 Disp_AddRef,
998 Disp_Release,
1000 Disp_GetTypeInfoCount,
1001 Disp_GetTypeInfo,
1002 Disp_GetIDsOfNames,
1003 Disp_Invoke
1006 static HRESULT WINAPI Enum_QueryInterface(
1007 IEnumConnections* This,
1008 REFIID riid,
1009 void **ppvObject)
1011 *ppvObject = NULL;
1013 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumConnections))
1015 *ppvObject = This;
1018 if (*ppvObject)
1020 IEnumConnections_AddRef(This);
1021 return S_OK;
1024 trace("no interface\n");
1025 return E_NOINTERFACE;
1028 static ULONG WINAPI Enum_AddRef(IEnumConnections* This)
1030 EnumCon *iface = impl_from_IEnumConnections(This);
1031 return InterlockedIncrement(&iface->refCount);
1034 static ULONG WINAPI Enum_Release(IEnumConnections* This)
1036 EnumCon *iface = impl_from_IEnumConnections(This);
1037 ULONG ret;
1039 ret = InterlockedDecrement(&iface->refCount);
1040 if (ret == 0)
1041 HeapFree(GetProcessHeap(),0,This);
1042 return ret;
1045 static HRESULT WINAPI Enum_Next(
1046 IEnumConnections* This,
1047 ULONG cConnections,
1048 LPCONNECTDATA rgcd,
1049 ULONG *pcFetched)
1051 EnumCon *iface = impl_from_IEnumConnections(This);
1053 if (cConnections > 0 && iface->idx < iface->pt->sinkCount)
1055 rgcd->pUnk = iface->pt->sink[iface->idx];
1056 IUnknown_AddRef(iface->pt->sink[iface->idx]);
1057 rgcd->dwCookie=0xff;
1058 if (pcFetched)
1059 *pcFetched = 1;
1060 iface->idx++;
1061 return S_OK;
1064 return E_FAIL;
1067 static HRESULT WINAPI Enum_Skip(
1068 IEnumConnections* This,
1069 ULONG cConnections)
1071 return E_FAIL;
1074 static HRESULT WINAPI Enum_Reset(
1075 IEnumConnections* This)
1077 return E_FAIL;
1080 static HRESULT WINAPI Enum_Clone(
1081 IEnumConnections* This,
1082 IEnumConnections **ppEnum)
1084 return E_FAIL;
1087 static const IEnumConnectionsVtbl enum_vtbl = {
1089 Enum_QueryInterface,
1090 Enum_AddRef,
1091 Enum_Release,
1092 Enum_Next,
1093 Enum_Skip,
1094 Enum_Reset,
1095 Enum_Clone
1098 static HRESULT WINAPI ConPt_QueryInterface(
1099 IConnectionPoint* This,
1100 REFIID riid,
1101 void **ppvObject)
1103 *ppvObject = NULL;
1105 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IConnectionPoint))
1107 *ppvObject = This;
1110 if (*ppvObject)
1112 IConnectionPoint_AddRef(This);
1113 return S_OK;
1116 trace("no interface\n");
1117 return E_NOINTERFACE;
1120 static ULONG WINAPI ConPt_AddRef(
1121 IConnectionPoint* This)
1123 ConPt *iface = impl_from_IConnectionPoint(This);
1124 return InterlockedIncrement(&iface->refCount);
1127 static ULONG WINAPI ConPt_Release(
1128 IConnectionPoint* This)
1130 ConPt *iface = impl_from_IConnectionPoint(This);
1131 ULONG ret;
1133 ret = InterlockedDecrement(&iface->refCount);
1134 if (ret == 0)
1136 if (iface->sinkCount > 0)
1138 int i;
1139 for (i = 0; i < iface->sinkCount; i++)
1141 if (iface->sink[i])
1142 IUnknown_Release(iface->sink[i]);
1144 HeapFree(GetProcessHeap(),0,iface->sink);
1146 HeapFree(GetProcessHeap(),0,This);
1148 return ret;
1151 static HRESULT WINAPI ConPt_GetConnectionInterface(
1152 IConnectionPoint* This,
1153 IID *pIID)
1155 static int i = 0;
1156 ConPt *iface = impl_from_IConnectionPoint(This);
1157 if (i==0)
1159 i++;
1160 return E_FAIL;
1162 else
1163 memcpy(pIID,&iface->id,sizeof(GUID));
1164 return S_OK;
1167 static HRESULT WINAPI ConPt_GetConnectionPointContainer(
1168 IConnectionPoint* This,
1169 IConnectionPointContainer **ppCPC)
1171 ConPt *iface = impl_from_IConnectionPoint(This);
1173 *ppCPC = &iface->container->IConnectionPointContainer_iface;
1174 return S_OK;
1177 static HRESULT WINAPI ConPt_Advise(
1178 IConnectionPoint* This,
1179 IUnknown *pUnkSink,
1180 DWORD *pdwCookie)
1182 ConPt *iface = impl_from_IConnectionPoint(This);
1184 if (iface->sinkCount == 0)
1185 iface->sink = HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown*));
1186 else
1187 iface->sink = HeapReAlloc(GetProcessHeap(),0,iface->sink,sizeof(IUnknown*)*(iface->sinkCount+1));
1188 iface->sink[iface->sinkCount] = pUnkSink;
1189 IUnknown_AddRef(pUnkSink);
1190 iface->sinkCount++;
1191 *pdwCookie = iface->sinkCount;
1192 return S_OK;
1195 static HRESULT WINAPI ConPt_Unadvise(
1196 IConnectionPoint* This,
1197 DWORD dwCookie)
1199 ConPt *iface = impl_from_IConnectionPoint(This);
1201 if (dwCookie > iface->sinkCount)
1202 return E_FAIL;
1203 else
1205 IUnknown_Release(iface->sink[dwCookie-1]);
1206 iface->sink[dwCookie-1] = NULL;
1208 return S_OK;
1211 static HRESULT WINAPI ConPt_EnumConnections(
1212 IConnectionPoint* This,
1213 IEnumConnections **ppEnum)
1215 EnumCon *ec;
1217 ec = HeapAlloc(GetProcessHeap(),0,sizeof(EnumCon));
1218 ec->IEnumConnections_iface.lpVtbl = &enum_vtbl;
1219 ec->refCount = 1;
1220 ec->pt = impl_from_IConnectionPoint(This);
1221 ec->idx = 0;
1222 *ppEnum = &ec->IEnumConnections_iface;
1224 return S_OK;
1227 static const IConnectionPointVtbl point_vtbl = {
1228 ConPt_QueryInterface,
1229 ConPt_AddRef,
1230 ConPt_Release,
1232 ConPt_GetConnectionInterface,
1233 ConPt_GetConnectionPointContainer,
1234 ConPt_Advise,
1235 ConPt_Unadvise,
1236 ConPt_EnumConnections
1239 static HRESULT WINAPI EnumPt_QueryInterface(
1240 IEnumConnectionPoints* This,
1241 REFIID riid,
1242 void **ppvObject)
1244 *ppvObject = NULL;
1246 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumConnectionPoints))
1248 *ppvObject = This;
1251 if (*ppvObject)
1253 IEnumConnectionPoints_AddRef(This);
1254 return S_OK;
1257 trace("no interface\n");
1258 return E_NOINTERFACE;
1261 static ULONG WINAPI EnumPt_AddRef(IEnumConnectionPoints* This)
1263 EnumPt *iface = impl_from_IEnumConnectionPoints(This);
1264 return InterlockedIncrement(&iface->refCount);
1267 static ULONG WINAPI EnumPt_Release(IEnumConnectionPoints* This)
1269 EnumPt *iface = impl_from_IEnumConnectionPoints(This);
1270 ULONG ret;
1272 ret = InterlockedDecrement(&iface->refCount);
1273 if (ret == 0)
1274 HeapFree(GetProcessHeap(),0,This);
1275 return ret;
1278 static HRESULT WINAPI EnumPt_Next(
1279 IEnumConnectionPoints* This,
1280 ULONG cConnections,
1281 IConnectionPoint **rgcd,
1282 ULONG *pcFetched)
1284 EnumPt *iface = impl_from_IEnumConnectionPoints(This);
1286 if (cConnections > 0 && iface->idx < iface->container->ptCount)
1288 *rgcd = iface->container->pt[iface->idx];
1289 IConnectionPoint_AddRef(iface->container->pt[iface->idx]);
1290 if (pcFetched)
1291 *pcFetched = 1;
1292 iface->idx++;
1293 return S_OK;
1296 return E_FAIL;
1299 static HRESULT WINAPI EnumPt_Skip(
1300 IEnumConnectionPoints* This,
1301 ULONG cConnections)
1303 return E_FAIL;
1306 static HRESULT WINAPI EnumPt_Reset(
1307 IEnumConnectionPoints* This)
1309 return E_FAIL;
1312 static HRESULT WINAPI EnumPt_Clone(
1313 IEnumConnectionPoints* This,
1314 IEnumConnectionPoints **ppEnumPt)
1316 return E_FAIL;
1319 static const IEnumConnectionPointsVtbl enumpt_vtbl = {
1321 EnumPt_QueryInterface,
1322 EnumPt_AddRef,
1323 EnumPt_Release,
1324 EnumPt_Next,
1325 EnumPt_Skip,
1326 EnumPt_Reset,
1327 EnumPt_Clone
1330 static HRESULT WINAPI Contain_QueryInterface(
1331 IConnectionPointContainer* This,
1332 REFIID riid,
1333 void **ppvObject)
1335 *ppvObject = NULL;
1337 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IConnectionPointContainer))
1339 *ppvObject = This;
1342 if (*ppvObject)
1344 IConnectionPointContainer_AddRef(This);
1345 return S_OK;
1348 trace("no interface\n");
1349 return E_NOINTERFACE;
1352 static ULONG WINAPI Contain_AddRef(
1353 IConnectionPointContainer* This)
1355 Contain *iface = impl_from_IConnectionPointContainer(This);
1356 return InterlockedIncrement(&iface->refCount);
1359 static ULONG WINAPI Contain_Release(
1360 IConnectionPointContainer* This)
1362 Contain *iface = impl_from_IConnectionPointContainer(This);
1363 ULONG ret;
1365 ret = InterlockedDecrement(&iface->refCount);
1366 if (ret == 0)
1368 if (iface->ptCount > 0)
1370 int i;
1371 for (i = 0; i < iface->ptCount; i++)
1372 IConnectionPoint_Release(iface->pt[i]);
1373 HeapFree(GetProcessHeap(),0,iface->pt);
1375 HeapFree(GetProcessHeap(),0,This);
1377 return ret;
1380 static HRESULT WINAPI Contain_EnumConnectionPoints(
1381 IConnectionPointContainer* This,
1382 IEnumConnectionPoints **ppEnum)
1384 EnumPt *ec;
1386 ec = HeapAlloc(GetProcessHeap(),0,sizeof(EnumPt));
1387 ec->IEnumConnectionPoints_iface.lpVtbl = &enumpt_vtbl;
1388 ec->refCount = 1;
1389 ec->idx= 0;
1390 ec->container = impl_from_IConnectionPointContainer(This);
1391 *ppEnum = &ec->IEnumConnectionPoints_iface;
1393 return S_OK;
1396 static HRESULT WINAPI Contain_FindConnectionPoint(
1397 IConnectionPointContainer* This,
1398 REFIID riid,
1399 IConnectionPoint **ppCP)
1401 Contain *iface = impl_from_IConnectionPointContainer(This);
1402 ConPt *pt;
1404 if (!IsEqualIID(riid, &IID_NULL) || iface->ptCount ==0)
1406 pt = HeapAlloc(GetProcessHeap(),0,sizeof(ConPt));
1407 pt->IConnectionPoint_iface.lpVtbl = &point_vtbl;
1408 pt->refCount = 1;
1409 pt->sinkCount = 0;
1410 pt->sink = NULL;
1411 pt->container = iface;
1412 pt->id = IID_IDispatch;
1414 if (iface->ptCount == 0)
1415 iface->pt =HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown*));
1416 else
1417 iface->pt = HeapReAlloc(GetProcessHeap(),0,iface->pt,sizeof(IUnknown*)*(iface->ptCount+1));
1418 iface->pt[iface->ptCount] = &pt->IConnectionPoint_iface;
1419 iface->ptCount++;
1421 *ppCP = &pt->IConnectionPoint_iface;
1423 else
1425 *ppCP = iface->pt[0];
1426 IConnectionPoint_AddRef(*ppCP);
1429 return S_OK;
1432 static const IConnectionPointContainerVtbl contain_vtbl = {
1433 Contain_QueryInterface,
1434 Contain_AddRef,
1435 Contain_Release,
1437 Contain_EnumConnectionPoints,
1438 Contain_FindConnectionPoint
1441 static void test_IConnectionPoint(void)
1443 HRESULT rc;
1444 ULONG ref;
1445 IConnectionPoint *point;
1446 Contain *container;
1447 Disp *dispatch;
1448 DWORD cookie = 0xffffffff;
1449 DISPPARAMS params;
1450 VARIANT vars[10];
1452 container = HeapAlloc(GetProcessHeap(),0,sizeof(Contain));
1453 container->IConnectionPointContainer_iface.lpVtbl = &contain_vtbl;
1454 container->refCount = 1;
1455 container->ptCount = 0;
1456 container->pt = NULL;
1458 dispatch = HeapAlloc(GetProcessHeap(),0,sizeof(Disp));
1459 dispatch->IDispatch_iface.lpVtbl = &disp_vtbl;
1460 dispatch->refCount = 1;
1462 rc = pConnectToConnectionPoint((IUnknown*)&dispatch->IDispatch_iface, &IID_NULL, TRUE,
1463 (IUnknown*)&container->IConnectionPointContainer_iface, &cookie, &point);
1464 ok(rc == S_OK, "pConnectToConnectionPoint failed with %lx\n",rc);
1465 ok(point != NULL, "returned ConnectionPoint is NULL\n");
1466 ok(cookie != 0xffffffff, "invalid cookie returned\n");
1468 rc = pIConnectionPoint_SimpleInvoke(point,0xa0,NULL);
1469 ok(rc == S_OK, "pConnectToConnectionPoint failed with %lx\n",rc);
1471 memset(&params, 0xc0, sizeof(params));
1472 memset(vars, 0xc0, sizeof(vars));
1473 rc = pSHPackDispParams(&params, vars, 2, VT_I4, 0xdeadbeef, VT_BSTR, 0xdeadcafe);
1474 ok(rc == S_OK, "SHPackDispParams failed: %08lx\n", rc);
1476 rc = pIConnectionPoint_SimpleInvoke(point,0xa1,&params);
1477 ok(rc == S_OK, "pConnectToConnectionPoint failed with %lx\n",rc);
1479 rc = pConnectToConnectionPoint(NULL, &IID_NULL, FALSE,
1480 (IUnknown*)&container->IConnectionPointContainer_iface, &cookie, NULL);
1481 ok(rc == S_OK, "pConnectToConnectionPoint failed with %lx\n",rc);
1483 /* MSDN says this should be required but it crashes on XP
1484 IUnknown_Release(point);
1486 ref = IConnectionPointContainer_Release(&container->IConnectionPointContainer_iface);
1487 ok(ref == 0, "leftover IConnectionPointContainer reference %li\n",ref);
1488 ref = IDispatch_Release(&dispatch->IDispatch_iface);
1489 ok(ref == 0, "leftover IDispatch reference %li\n",ref);
1492 typedef struct _propbag
1494 IPropertyBag IPropertyBag_iface;
1495 LONG refCount;
1497 } PropBag;
1499 static inline PropBag *impl_from_IPropertyBag(IPropertyBag *iface)
1501 return CONTAINING_RECORD(iface, PropBag, IPropertyBag_iface);
1505 static HRESULT WINAPI Prop_QueryInterface(
1506 IPropertyBag* This,
1507 REFIID riid,
1508 void **ppvObject)
1510 *ppvObject = NULL;
1512 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPropertyBag))
1514 *ppvObject = This;
1517 if (*ppvObject)
1519 IPropertyBag_AddRef(This);
1520 return S_OK;
1523 trace("no interface\n");
1524 return E_NOINTERFACE;
1527 static ULONG WINAPI Prop_AddRef(
1528 IPropertyBag* This)
1530 PropBag *iface = impl_from_IPropertyBag(This);
1531 return InterlockedIncrement(&iface->refCount);
1534 static ULONG WINAPI Prop_Release(
1535 IPropertyBag* This)
1537 PropBag *iface = impl_from_IPropertyBag(This);
1538 ULONG ret;
1540 ret = InterlockedDecrement(&iface->refCount);
1541 if (ret == 0)
1542 HeapFree(GetProcessHeap(),0,This);
1543 return ret;
1546 static HRESULT WINAPI Prop_Read(
1547 IPropertyBag* This,
1548 LPCOLESTR pszPropName,
1549 VARIANT *pVar,
1550 IErrorLog *pErrorLog)
1552 V_VT(pVar) = VT_BLOB|VT_BYREF;
1553 V_BYREF(pVar) = (LPVOID)0xdeadcafe;
1554 return S_OK;
1557 static HRESULT WINAPI Prop_Write(
1558 IPropertyBag* This,
1559 LPCOLESTR pszPropName,
1560 VARIANT *pVar)
1562 return S_OK;
1566 static const IPropertyBagVtbl prop_vtbl = {
1567 Prop_QueryInterface,
1568 Prop_AddRef,
1569 Prop_Release,
1571 Prop_Read,
1572 Prop_Write
1575 static void test_SHPropertyBag_ReadLONG(void)
1577 PropBag *pb;
1578 HRESULT rc;
1579 LONG out;
1580 static const WCHAR szName1[] = {'n','a','m','e','1',0};
1582 pb = HeapAlloc(GetProcessHeap(),0,sizeof(PropBag));
1583 pb->refCount = 1;
1584 pb->IPropertyBag_iface.lpVtbl = &prop_vtbl;
1586 out = 0xfeedface;
1587 rc = pSHPropertyBag_ReadLONG(NULL, szName1, &out);
1588 ok(rc == E_INVALIDARG || broken(rc == S_OK), "incorrect return %lx\n",rc);
1589 ok(out == 0xfeedface, "value should not have changed\n");
1590 rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, NULL, &out);
1591 ok(rc == E_INVALIDARG || broken(rc == S_OK) || broken(rc == S_FALSE), "incorrect return %lx\n",rc);
1592 ok(out == 0xfeedface, "value should not have changed\n");
1593 rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, szName1, NULL);
1594 ok(rc == E_INVALIDARG || broken(rc == S_OK) || broken(rc == S_FALSE), "incorrect return %lx\n",rc);
1595 rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, szName1, &out);
1596 ok(rc == DISP_E_BADVARTYPE || broken(rc == S_OK) || broken(rc == S_FALSE), "incorrect return %lx\n",rc);
1597 ok(out == 0xfeedface || broken(out == 0xfeedfa00), "value should not have changed %lx\n",out);
1598 IPropertyBag_Release(&pb->IPropertyBag_iface);
1601 static void test_SHSetWindowBits(void)
1603 HWND hwnd;
1604 DWORD style, styleold;
1605 WNDCLASSA clsA;
1607 clsA.style = 0;
1608 clsA.lpfnWndProc = DefWindowProcA;
1609 clsA.cbClsExtra = 0;
1610 clsA.cbWndExtra = 0;
1611 clsA.hInstance = GetModuleHandleA(NULL);
1612 clsA.hIcon = 0;
1613 clsA.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
1614 clsA.hbrBackground = NULL;
1615 clsA.lpszMenuName = NULL;
1616 clsA.lpszClassName = "Shlwapi test class";
1617 RegisterClassA(&clsA);
1619 hwnd = CreateWindowA("Shlwapi test class", "Test", WS_VISIBLE, 0, 0, 100, 100,
1620 NULL, NULL, GetModuleHandleA(NULL), 0);
1621 ok(IsWindow(hwnd), "failed to create window\n");
1623 /* null window */
1624 SetLastError(0xdeadbeef);
1625 style = pSHSetWindowBits(NULL, GWL_STYLE, 0, 0);
1626 ok(style == 0, "expected 0 retval, got %ld\n", style);
1627 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE,
1628 "expected ERROR_INVALID_WINDOW_HANDLE, got %ld\n", GetLastError());
1630 /* zero mask, zero flags */
1631 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1632 style = pSHSetWindowBits(hwnd, GWL_STYLE, 0, 0);
1633 ok(styleold == style, "expected old style\n");
1634 ok(styleold == GetWindowLongA(hwnd, GWL_STYLE), "expected to keep old style\n");
1636 /* test mask */
1637 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1638 ok(styleold & WS_VISIBLE, "expected WS_VISIBLE\n");
1639 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1641 ok(style == styleold, "expected previous style, got %lx\n", style);
1642 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1644 /* test mask, unset style bit used */
1645 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1646 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1647 ok(style == styleold, "expected previous style, got %lx\n", style);
1648 ok(styleold == GetWindowLongA(hwnd, GWL_STYLE), "expected to keep old style\n");
1650 /* set back with flags */
1651 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1652 style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, WS_VISIBLE);
1653 ok(style == styleold, "expected previous style, got %lx\n", style);
1654 ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "expected updated style\n");
1656 /* reset and try to set without a mask */
1657 pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
1658 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1659 styleold = GetWindowLongA(hwnd, GWL_STYLE);
1660 style = pSHSetWindowBits(hwnd, GWL_STYLE, 0, WS_VISIBLE);
1661 ok(style == styleold, "expected previous style, got %lx\n", style);
1662 ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
1664 DestroyWindow(hwnd);
1666 UnregisterClassA("Shlwapi test class", GetModuleHandleA(NULL));
1669 static void test_SHFormatDateTimeA(const SYSTEMTIME *st)
1671 FILETIME filetime;
1672 FILETIME filetimeCheck;
1673 SYSTEMTIME universalSystemTime;
1674 CHAR buff[100], buff2[100], buff3[100];
1675 BOOL dstMatch;
1676 DWORD flags;
1677 INT ret;
1679 /* SHFormatDateTime expects input as utc */
1680 TzSpecificLocalTimeToSystemTime(NULL, st, &universalSystemTime);
1681 SystemTimeToFileTime(&universalSystemTime, &filetime);
1683 SystemTimeToFileTime(st, &filetimeCheck);
1684 LocalFileTimeToFileTime(&filetimeCheck, &filetimeCheck);
1685 dstMatch = (filetime.dwHighDateTime == filetimeCheck.dwHighDateTime) &&
1686 (filetime.dwLowDateTime == filetimeCheck.dwLowDateTime);
1688 /* no way to get required buffer length here */
1689 ret = pSHFormatDateTimeA(&filetime, NULL, NULL, 0);
1690 ok(ret == 0, "got %d\n", ret);
1692 SetLastError(0xdeadbeef);
1693 buff[0] = 'a'; buff[1] = 0;
1694 ret = pSHFormatDateTimeA(&filetime, NULL, buff, 0);
1695 ok(ret == 0, "got %d\n", ret);
1696 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError());
1697 ok(buff[0] == 'a', "expected same string, got %s\n", buff);
1699 /* flags needs to have FDTF_NOAUTOREADINGORDER for these tests to succeed on Vista+ */
1701 /* all combinations documented as invalid succeeded */
1702 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTTIME | FDTF_LONGTIME;
1703 SetLastError(0xdeadbeef);
1704 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1705 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1706 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError());
1708 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_LONGDATE;
1709 SetLastError(0xdeadbeef);
1710 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1711 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1712 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError());
1714 flags = FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE;
1715 SetLastError(0xdeadbeef);
1716 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1717 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1718 ok(GetLastError() == 0xdeadbeef,
1719 "expected 0xdeadbeef, got %ld\n", GetLastError());
1721 flags = FDTF_DEFAULT;
1722 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1723 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1725 buff2[0] = '\0';
1726 flags = FDTF_SHORTDATE | FDTF_SHORTTIME;
1727 ret = pSHFormatDateTimeA(&filetime, &flags, buff2, sizeof(buff2));
1728 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1729 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff, buff2);
1731 buff2[0] = '\0';
1732 ret = pSHFormatDateTimeA(&filetime, 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", buff, buff2);
1736 /* now check returned strings */
1737 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTTIME;
1738 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1739 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1740 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, TIME_NOSECONDS | LOCALE_USE_CP_ACP, st, NULL, buff2, sizeof(buff2));
1741 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1742 ok(lstrcmpA(buff, buff2) == 0 || broken(!dstMatch) /* pre Windows 7 */,
1743 "expected (%s), got (%s)\n", buff2, buff);
1745 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGTIME;
1746 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1747 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1748 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP, st, NULL, buff2, sizeof(buff2));
1749 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1750 ok(lstrcmpA(buff, buff2) == 0 || broken(!dstMatch) /* pre Windows 7 */,
1751 "expected (%s), got (%s)\n", buff2, buff);
1753 /* both time flags */
1754 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGTIME | FDTF_SHORTTIME;
1755 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1756 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1757 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP, st, NULL, buff2, sizeof(buff2));
1758 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1759 ok(lstrcmpA(buff, buff2) == 0 || broken(!dstMatch) /* pre Windows 7 */,
1760 "expected (%s), got (%s)\n", buff2, buff);
1762 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE;
1763 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1764 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1765 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_SHORTDATE | LOCALE_USE_CP_ACP, st, NULL, buff2, sizeof(buff2));
1766 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1767 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1769 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE;
1770 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1771 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1772 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_LONGDATE | LOCALE_USE_CP_ACP, st, NULL, buff2, sizeof(buff2));
1773 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1774 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1776 /* both date flags */
1777 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_SHORTDATE;
1778 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1779 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1780 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_LONGDATE | LOCALE_USE_CP_ACP, st, NULL, buff2, sizeof(buff2));
1781 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1782 ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
1784 /* various combinations of date/time flags */
1785 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_SHORTTIME;
1786 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1787 ok(ret == lstrlenA(buff)+1, "got %d, length %d\n", ret, lstrlenA(buff)+1);
1788 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, TIME_NOSECONDS | LOCALE_USE_CP_ACP, st, NULL, buff3, sizeof(buff3));
1789 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1790 ok(lstrcmpA(buff3, buff + lstrlenA(buff) - lstrlenA(buff3)) == 0 || broken(!dstMatch) /* pre Windows 7 */,
1791 "expected (%s), got (%s) for time part\n",
1792 buff3, buff + lstrlenA(buff) - lstrlenA(buff3));
1793 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_LONGDATE | LOCALE_USE_CP_ACP, st, NULL, buff2, sizeof(buff2));
1794 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1795 buff[lstrlenA(buff2)] = '\0';
1796 ok(lstrcmpA(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1797 buff2, buff);
1799 flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_LONGTIME;
1800 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1801 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1802 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP, st, NULL, buff3, sizeof(buff3));
1803 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1804 ok(lstrcmpA(buff3, buff + lstrlenA(buff) - lstrlenA(buff3)) == 0 || broken(!dstMatch) /* pre Windows 7 */,
1805 "expected (%s), got (%s) for time part\n",
1806 buff3, buff + lstrlenA(buff) - lstrlenA(buff3));
1807 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_LONGDATE | LOCALE_USE_CP_ACP, st, NULL, buff2, sizeof(buff2));
1808 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1809 buff[lstrlenA(buff2)] = '\0';
1810 ok(lstrcmpA(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1811 buff2, buff);
1813 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_SHORTTIME;
1814 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1815 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1816 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_SHORTDATE | LOCALE_USE_CP_ACP, st, NULL, buff2, sizeof(buff2));
1817 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1818 strcat(buff2, " ");
1819 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, TIME_NOSECONDS | LOCALE_USE_CP_ACP, st, NULL, buff3, sizeof(buff3));
1820 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1821 strcat(buff2, buff3);
1822 ok(lstrcmpA(buff, buff2) == 0 || broken(!dstMatch) /* pre Windows 7 */,
1823 "expected (%s), got (%s)\n", buff2, buff);
1825 flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_LONGTIME;
1826 ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
1827 ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
1828 ret = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_SHORTDATE | LOCALE_USE_CP_ACP, st, NULL, buff2, sizeof(buff2));
1829 ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
1830 strcat(buff2, " ");
1831 ret = GetTimeFormatA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP, st, NULL, buff3, sizeof(buff3));
1832 ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
1833 strcat(buff2, buff3);
1834 ok(lstrcmpA(buff, buff2) == 0 || broken(!dstMatch) /* pre Windows 7 */,
1835 "expected (%s), got (%s)\n", buff2, buff);
1838 static void test_SHFormatDateTimeW(void)
1840 FILETIME filetime;
1841 SYSTEMTIME universalSystemTime;
1842 WCHAR buff[100], buff2[100], buff3[100], *p1, *p2;
1843 SYSTEMTIME st;
1844 DWORD flags;
1845 INT ret;
1846 static const WCHAR spaceW[] = {' ',0};
1847 #define UNICODE_LTR_MARK 0x200e
1848 #define UNICODE_RTL_MARK 0x200f
1850 if (0)
1852 /* crashes on native */
1853 pSHFormatDateTimeW(NULL, NULL, NULL, 0);
1856 GetLocalTime(&st);
1857 /* SHFormatDateTime expects input as utc */
1858 TzSpecificLocalTimeToSystemTime(NULL, &st, &universalSystemTime);
1859 SystemTimeToFileTime(&universalSystemTime, &filetime);
1861 /* no way to get required buffer length here */
1862 SetLastError(0xdeadbeef);
1863 ret = pSHFormatDateTimeW(&filetime, NULL, NULL, 0);
1864 ok(ret == 0, "expected 0, got %d\n", ret);
1865 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError());
1867 SetLastError(0xdeadbeef);
1868 buff[0] = 'a'; buff[1] = 0;
1869 ret = pSHFormatDateTimeW(&filetime, NULL, buff, 0);
1870 ok(ret == 0, "expected 0, got %d\n", ret);
1871 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError());
1872 ok(buff[0] == 'a', "expected same string\n");
1874 /* all combinations documented as invalid succeeded */
1875 flags = FDTF_SHORTTIME | FDTF_LONGTIME;
1876 SetLastError(0xdeadbeef);
1877 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1878 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1879 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1880 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError());
1882 flags = FDTF_SHORTDATE | FDTF_LONGDATE;
1883 SetLastError(0xdeadbeef);
1884 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1885 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1886 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1887 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError());
1889 flags = FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE;
1890 SetLastError(0xdeadbeef);
1891 buff[0] = 0; /* NT4 doesn't clear the buffer on failure */
1892 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1893 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1894 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1895 ok(GetLastError() == 0xdeadbeef,
1896 "expected 0xdeadbeef, got %ld\n", GetLastError());
1898 /* now check returned strings */
1899 flags = FDTF_SHORTTIME;
1900 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1901 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1902 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1903 SetLastError(0xdeadbeef);
1904 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff2, ARRAY_SIZE(buff2));
1905 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1906 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1908 flags = FDTF_LONGTIME;
1909 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1910 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1911 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1912 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, ARRAY_SIZE(buff2));
1913 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1914 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1916 /* both time flags */
1917 flags = FDTF_LONGTIME | FDTF_SHORTTIME;
1918 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1919 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1920 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1921 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, ARRAY_SIZE(buff2));
1922 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1923 ok(lstrcmpW(buff, buff2) == 0, "expected equal string\n");
1925 flags = FDTF_SHORTDATE;
1926 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1927 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1928 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1929 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, ARRAY_SIZE(buff2));
1930 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1931 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1933 flags = FDTF_LONGDATE;
1934 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1935 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1936 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1937 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, ARRAY_SIZE(buff2));
1938 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1939 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1941 /* both date flags */
1942 flags = FDTF_LONGDATE | FDTF_SHORTDATE;
1943 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1944 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1945 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1946 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, ARRAY_SIZE(buff2));
1947 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1948 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
1950 /* various combinations of date/time flags */
1951 flags = FDTF_LONGDATE | FDTF_SHORTTIME;
1952 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1953 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1954 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1955 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, ARRAY_SIZE(buff3));
1956 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1957 ok(lstrcmpW(buff3, buff + lstrlenW(buff) - lstrlenW(buff3)) == 0,
1958 "expected (%s), got (%s) for time part\n",
1959 wine_dbgstr_w(buff3), wine_dbgstr_w(buff + lstrlenW(buff) - lstrlenW(buff3)));
1960 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, ARRAY_SIZE(buff2));
1961 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1962 p1 = buff;
1963 p2 = buff2;
1964 while (*p2 != '\0')
1966 while (*p1 == UNICODE_LTR_MARK || *p1 == UNICODE_RTL_MARK)
1967 p1++;
1968 while (*p2 == UNICODE_LTR_MARK || *p2 == UNICODE_RTL_MARK)
1969 p2++;
1970 p1++;
1971 p2++;
1973 *p1 = '\0';
1974 ok(lstrcmpW(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
1975 wine_dbgstr_w(buff2), wine_dbgstr_w(buff));
1977 flags = FDTF_LONGDATE | FDTF_LONGTIME;
1978 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
1979 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
1980 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
1981 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, ARRAY_SIZE(buff3));
1982 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
1983 ok(lstrcmpW(buff3, buff + lstrlenW(buff) - lstrlenW(buff3)) == 0,
1984 "expected (%s), got (%s) for time part\n",
1985 wine_dbgstr_w(buff3), wine_dbgstr_w(buff + lstrlenW(buff) - lstrlenW(buff3)));
1986 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, ARRAY_SIZE(buff2));
1987 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
1988 p1 = buff;
1989 p2 = buff2;
1990 while (*p2 != '\0')
1992 while (*p1 == UNICODE_LTR_MARK || *p1 == UNICODE_RTL_MARK)
1993 p1++;
1994 while (*p2 == UNICODE_LTR_MARK || *p2 == UNICODE_RTL_MARK)
1995 p2++;
1996 p1++;
1997 p2++;
1999 *p1 = '\0';
2000 ok(lstrcmpW(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
2001 wine_dbgstr_w(buff2), wine_dbgstr_w(buff));
2003 flags = FDTF_SHORTDATE | FDTF_SHORTTIME;
2004 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
2005 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
2006 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
2007 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, ARRAY_SIZE(buff2));
2008 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
2009 lstrcatW(buff2, spaceW);
2010 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, ARRAY_SIZE(buff3));
2011 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
2012 lstrcatW(buff2, buff3);
2013 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
2015 flags = FDTF_SHORTDATE | FDTF_LONGTIME;
2016 ret = pSHFormatDateTimeW(&filetime, &flags, buff, ARRAY_SIZE(buff));
2017 ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
2018 "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
2019 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, ARRAY_SIZE(buff2));
2020 ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
2021 lstrcatW(buff2, spaceW);
2022 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, ARRAY_SIZE(buff3));
2023 ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
2024 lstrcatW(buff2, buff3);
2025 ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
2028 static void test_SHGetObjectCompatFlags(void)
2030 struct compat_value {
2031 CHAR nameA[30];
2032 DWORD value;
2035 struct compat_value values[] = {
2036 { "OTNEEDSSFCACHE", 0x1 },
2037 { "NO_WEBVIEW", 0x2 },
2038 { "UNBINDABLE", 0x4 },
2039 { "PINDLL", 0x8 },
2040 { "NEEDSFILESYSANCESTOR", 0x10 },
2041 { "NOTAFILESYSTEM", 0x20 },
2042 { "CTXMENU_NOVERBS", 0x40 },
2043 { "CTXMENU_LIMITEDQI", 0x80 },
2044 { "COCREATESHELLFOLDERONLY", 0x100 },
2045 { "NEEDSSTORAGEANCESTOR", 0x200 },
2046 { "NOLEGACYWEBVIEW", 0x400 },
2047 { "CTXMENU_XPQCMFLAGS", 0x1000 },
2048 { "NOIPROPERTYSTORE", 0x2000 }
2051 static const char compat_path[] = "Software\\Microsoft\\Windows\\CurrentVersion\\ShellCompatibility\\Objects";
2052 CHAR keyA[39]; /* {CLSID} */
2053 HKEY root;
2054 DWORD ret;
2055 int i;
2057 /* null args */
2058 ret = pSHGetObjectCompatFlags(NULL, NULL);
2059 ok(ret == 0, "got %ld\n", ret);
2061 ret = RegOpenKeyA(HKEY_LOCAL_MACHINE, compat_path, &root);
2062 if (ret != ERROR_SUCCESS)
2064 skip("No compatibility class data found\n");
2065 return;
2068 for (i = 0; RegEnumKeyA(root, i, keyA, sizeof(keyA)) == ERROR_SUCCESS; i++)
2070 HKEY clsid_key;
2072 if (RegOpenKeyA(root, keyA, &clsid_key) == ERROR_SUCCESS)
2074 CHAR valueA[30];
2075 DWORD expected = 0, got, length = sizeof(valueA);
2076 CLSID clsid;
2077 int v;
2079 for (v = 0; RegEnumValueA(clsid_key, v, valueA, &length, NULL, NULL, NULL, NULL) == ERROR_SUCCESS; v++)
2081 int j;
2083 for (j = 0; j < ARRAY_SIZE(values); j++)
2084 if (lstrcmpA(values[j].nameA, valueA) == 0)
2086 expected |= values[j].value;
2087 break;
2090 length = sizeof(valueA);
2093 pGUIDFromStringA(keyA, &clsid);
2094 got = pSHGetObjectCompatFlags(NULL, &clsid);
2095 ok(got == expected, "got 0x%08lx, expected 0x%08lx. Key %s\n", got, expected, keyA);
2097 RegCloseKey(clsid_key);
2101 RegCloseKey(root);
2104 typedef struct {
2105 IOleCommandTarget IOleCommandTarget_iface;
2106 LONG ref;
2107 } IOleCommandTargetImpl;
2109 static inline IOleCommandTargetImpl *impl_from_IOleCommandTarget(IOleCommandTarget *iface)
2111 return CONTAINING_RECORD(iface, IOleCommandTargetImpl, IOleCommandTarget_iface);
2114 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl;
2116 static IOleCommandTarget* IOleCommandTargetImpl_Construct(void)
2118 IOleCommandTargetImpl *obj;
2120 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2121 obj->IOleCommandTarget_iface.lpVtbl = &IOleCommandTargetImpl_Vtbl;
2122 obj->ref = 1;
2124 return &obj->IOleCommandTarget_iface;
2127 static HRESULT WINAPI IOleCommandTargetImpl_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppvObj)
2129 IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface);
2131 if (IsEqualIID(riid, &IID_IUnknown) ||
2132 IsEqualIID(riid, &IID_IOleCommandTarget))
2134 *ppvObj = This;
2137 if(*ppvObj)
2139 IOleCommandTarget_AddRef(iface);
2140 return S_OK;
2143 return E_NOINTERFACE;
2146 static ULONG WINAPI IOleCommandTargetImpl_AddRef(IOleCommandTarget *iface)
2148 IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface);
2149 return InterlockedIncrement(&This->ref);
2152 static ULONG WINAPI IOleCommandTargetImpl_Release(IOleCommandTarget *iface)
2154 IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface);
2155 ULONG ref = InterlockedDecrement(&This->ref);
2157 if (!ref)
2159 HeapFree(GetProcessHeap(), 0, This);
2160 return 0;
2162 return ref;
2165 static HRESULT WINAPI IOleCommandTargetImpl_QueryStatus(
2166 IOleCommandTarget *iface, const GUID *group, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText)
2168 return E_NOTIMPL;
2171 static HRESULT WINAPI IOleCommandTargetImpl_Exec(
2172 IOleCommandTarget *iface,
2173 const GUID *CmdGroup,
2174 DWORD nCmdID,
2175 DWORD nCmdexecopt,
2176 VARIANT *pvaIn,
2177 VARIANT *pvaOut)
2179 add_call(&trace_got, 3, CmdGroup, (void*)(DWORD_PTR)nCmdID, (void*)(DWORD_PTR)nCmdexecopt, pvaIn, pvaOut);
2180 return S_OK;
2183 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl =
2185 IOleCommandTargetImpl_QueryInterface,
2186 IOleCommandTargetImpl_AddRef,
2187 IOleCommandTargetImpl_Release,
2188 IOleCommandTargetImpl_QueryStatus,
2189 IOleCommandTargetImpl_Exec
2192 typedef struct {
2193 IServiceProvider IServiceProvider_iface;
2194 LONG ref;
2195 } IServiceProviderImpl;
2197 static inline IServiceProviderImpl *impl_from_IServiceProvider(IServiceProvider *iface)
2199 return CONTAINING_RECORD(iface, IServiceProviderImpl, IServiceProvider_iface);
2202 typedef struct {
2203 IProfferService IProfferService_iface;
2204 LONG ref;
2205 } IProfferServiceImpl;
2207 static inline IProfferServiceImpl *impl_from_IProfferService(IProfferService *iface)
2209 return CONTAINING_RECORD(iface, IProfferServiceImpl, IProfferService_iface);
2213 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl;
2214 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl;
2216 static IServiceProvider* IServiceProviderImpl_Construct(void)
2218 IServiceProviderImpl *obj;
2220 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2221 obj->IServiceProvider_iface.lpVtbl = &IServiceProviderImpl_Vtbl;
2222 obj->ref = 1;
2224 return &obj->IServiceProvider_iface;
2227 static IProfferService* IProfferServiceImpl_Construct(void)
2229 IProfferServiceImpl *obj;
2231 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
2232 obj->IProfferService_iface.lpVtbl = &IProfferServiceImpl_Vtbl;
2233 obj->ref = 1;
2235 return &obj->IProfferService_iface;
2238 static HRESULT WINAPI IServiceProviderImpl_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppvObj)
2240 IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
2242 if (IsEqualIID(riid, &IID_IUnknown) ||
2243 IsEqualIID(riid, &IID_IServiceProvider))
2245 *ppvObj = This;
2248 if(*ppvObj)
2250 IServiceProvider_AddRef(iface);
2251 /* native uses redefined IID_IServiceProvider symbol, so we can't compare pointers */
2252 if (IsEqualIID(riid, &IID_IServiceProvider))
2253 add_call(&trace_got, 1, iface, &IID_IServiceProvider, 0, 0, 0);
2254 return S_OK;
2257 return E_NOINTERFACE;
2260 static ULONG WINAPI IServiceProviderImpl_AddRef(IServiceProvider *iface)
2262 IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
2263 return InterlockedIncrement(&This->ref);
2266 static ULONG WINAPI IServiceProviderImpl_Release(IServiceProvider *iface)
2268 IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
2269 ULONG ref = InterlockedDecrement(&This->ref);
2271 if (!ref)
2273 HeapFree(GetProcessHeap(), 0, This);
2274 return 0;
2276 return ref;
2279 static HRESULT WINAPI IServiceProviderImpl_QueryService(
2280 IServiceProvider *iface, REFGUID service, REFIID riid, void **ppv)
2282 /* native uses redefined pointer for IID_IOleCommandTarget, not one from uuid.lib */
2283 if (IsEqualIID(riid, &IID_IOleCommandTarget))
2285 add_call(&trace_got, 2, iface, service, &IID_IOleCommandTarget, 0, 0);
2286 *ppv = IOleCommandTargetImpl_Construct();
2288 if (IsEqualIID(riid, &IID_IProfferService))
2290 if (IsEqualIID(service, &IID_IProfferService))
2291 add_call(&trace_got, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2292 *ppv = IProfferServiceImpl_Construct();
2294 return S_OK;
2297 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl =
2299 IServiceProviderImpl_QueryInterface,
2300 IServiceProviderImpl_AddRef,
2301 IServiceProviderImpl_Release,
2302 IServiceProviderImpl_QueryService
2305 static void test_IUnknown_QueryServiceExec(void)
2307 IServiceProvider *provider;
2308 static const GUID dummy_serviceid = { 0xdeadbeef };
2309 static const GUID dummy_groupid = { 0xbeefbeef };
2310 call_trace_t trace_expected;
2311 HRESULT hr;
2313 provider = IServiceProviderImpl_Construct();
2315 /* null source pointer */
2316 hr = pIUnknown_QueryServiceExec(NULL, &dummy_serviceid, &dummy_groupid, 0, 0, 0, 0);
2317 ok(hr == E_FAIL ||
2318 hr == E_NOTIMPL, /* win 8 */
2319 "got 0x%08lx\n", hr);
2321 /* expected trace:
2322 IUnknown_QueryServiceExec( ptr1, serviceid, groupid, arg1, arg2, arg3, arg4);
2323 -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &prov );
2324 -> IServiceProvider_QueryService( prov, serviceid, &IID_IOleCommandTarget, &obj );
2325 -> IOleCommandTarget_Exec( obj, groupid, arg1, arg2, arg3, arg4 );
2327 init_call_trace(&trace_expected);
2329 add_call(&trace_expected, 1, provider, &IID_IServiceProvider, 0, 0, 0);
2330 add_call(&trace_expected, 2, provider, &dummy_serviceid, &IID_IOleCommandTarget, 0, 0);
2331 add_call(&trace_expected, 3, &dummy_groupid, (void*)0x1, (void*)0x2, (void*)0x3, (void*)0x4);
2333 init_call_trace(&trace_got);
2334 hr = pIUnknown_QueryServiceExec((IUnknown*)provider, &dummy_serviceid, &dummy_groupid, 0x1, 0x2, (void*)0x3, (void*)0x4);
2335 ok(hr == S_OK, "got 0x%08lx\n", hr);
2337 ok_trace(&trace_expected, &trace_got);
2339 free_call_trace(&trace_expected);
2340 free_call_trace(&trace_got);
2342 IServiceProvider_Release(provider);
2346 static HRESULT WINAPI IProfferServiceImpl_QueryInterface(IProfferService *iface, REFIID riid, void **ppvObj)
2348 IProfferServiceImpl *This = impl_from_IProfferService(iface);
2350 if (IsEqualIID(riid, &IID_IUnknown) ||
2351 IsEqualIID(riid, &IID_IProfferService))
2353 *ppvObj = This;
2355 else if (IsEqualIID(riid, &IID_IServiceProvider))
2357 *ppvObj = IServiceProviderImpl_Construct();
2358 add_call(&trace_got, 1, iface, &IID_IServiceProvider, 0, 0, 0);
2359 return S_OK;
2362 if(*ppvObj)
2364 IProfferService_AddRef(iface);
2365 return S_OK;
2368 return E_NOINTERFACE;
2371 static ULONG WINAPI IProfferServiceImpl_AddRef(IProfferService *iface)
2373 IProfferServiceImpl *This = impl_from_IProfferService(iface);
2374 return InterlockedIncrement(&This->ref);
2377 static ULONG WINAPI IProfferServiceImpl_Release(IProfferService *iface)
2379 IProfferServiceImpl *This = impl_from_IProfferService(iface);
2380 ULONG ref = InterlockedDecrement(&This->ref);
2382 if (!ref)
2384 HeapFree(GetProcessHeap(), 0, This);
2385 return 0;
2387 return ref;
2390 static HRESULT WINAPI IProfferServiceImpl_ProfferService(IProfferService *iface,
2391 REFGUID service, IServiceProvider *pService, DWORD *pCookie)
2393 *pCookie = 0xdeadbeef;
2394 add_call(&trace_got, 3, service, pService, pCookie, 0, 0);
2395 return S_OK;
2398 static HRESULT WINAPI IProfferServiceImpl_RevokeService(IProfferService *iface, DWORD cookie)
2400 add_call(&trace_got, 4, (void*)(DWORD_PTR)cookie, 0, 0, 0, 0);
2401 return S_OK;
2404 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl =
2406 IProfferServiceImpl_QueryInterface,
2407 IProfferServiceImpl_AddRef,
2408 IProfferServiceImpl_Release,
2409 IProfferServiceImpl_ProfferService,
2410 IProfferServiceImpl_RevokeService
2413 static void test_IUnknown_ProfferService(void)
2415 IServiceProvider *provider;
2416 IProfferService *proff;
2417 static const GUID dummy_serviceid = { 0xdeadbeef };
2418 call_trace_t trace_expected;
2419 HRESULT hr;
2420 DWORD cookie;
2422 provider = IServiceProviderImpl_Construct();
2423 proff = IProfferServiceImpl_Construct();
2425 /* null source pointer */
2426 hr = pIUnknown_ProfferService(NULL, &dummy_serviceid, 0, 0);
2427 ok(hr == E_FAIL ||
2428 hr == E_NOTIMPL, /* win 8 */
2429 "got 0x%08lx\n", hr);
2431 /* expected trace:
2432 IUnknown_ProfferService( ptr1, serviceid, arg1, arg2);
2433 -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &provider );
2434 -> IServiceProvider_QueryService( provider, &IID_IProfferService, &IID_IProfferService, &proffer );
2436 if (service pointer not null):
2437 -> IProfferService_ProfferService( proffer, serviceid, arg1, arg2 );
2438 else
2439 -> IProfferService_RevokeService( proffer, *arg2 );
2441 init_call_trace(&trace_expected);
2443 add_call(&trace_expected, 1, proff, &IID_IServiceProvider, 0, 0, 0);
2444 add_call(&trace_expected, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2445 add_call(&trace_expected, 3, &dummy_serviceid, provider, &cookie, 0, 0);
2447 init_call_trace(&trace_got);
2448 cookie = 0;
2449 hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, provider, &cookie);
2450 ok(hr == S_OK, "got 0x%08lx\n", hr);
2451 ok(cookie == 0xdeadbeef, "got %lx\n", cookie);
2453 ok_trace(&trace_expected, &trace_got);
2454 free_call_trace(&trace_got);
2455 free_call_trace(&trace_expected);
2457 /* same with ::Revoke path */
2458 init_call_trace(&trace_expected);
2460 add_call(&trace_expected, 1, proff, &IID_IServiceProvider, 0, 0, 0);
2461 add_call(&trace_expected, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
2462 add_call(&trace_expected, 4, (void*)(DWORD_PTR)cookie, 0, 0, 0, 0);
2464 init_call_trace(&trace_got);
2465 ok(cookie != 0, "got %lx\n", cookie);
2466 hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, 0, &cookie);
2467 ok(hr == S_OK, "got 0x%08lx\n", hr);
2468 ok(cookie == 0, "got %lx\n", cookie);
2469 ok_trace(&trace_expected, &trace_got);
2470 free_call_trace(&trace_got);
2471 free_call_trace(&trace_expected);
2473 IServiceProvider_Release(provider);
2474 IProfferService_Release(proff);
2477 static void test_SHCreateWorkerWindowA(void)
2479 WNDCLASSA cliA;
2480 char classA[20];
2481 HWND hwnd;
2482 LONG_PTR ret;
2483 BOOL res;
2485 hwnd = pSHCreateWorkerWindowA(0, NULL, 0, 0, 0, 0);
2486 ok(hwnd != 0, "expected window\n");
2488 GetClassNameA(hwnd, classA, 20);
2489 ok(lstrcmpA(classA, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA);
2491 ret = GetWindowLongPtrA(hwnd, 0);
2492 ok(ret == 0, "got %Id\n", ret);
2494 /* class info */
2495 memset(&cliA, 0, sizeof(cliA));
2496 res = GetClassInfoA(GetModuleHandleA("shlwapi.dll"), "WorkerA", &cliA);
2497 ok(res, "failed to get class info\n");
2498 ok(cliA.style == 0, "got 0x%08x\n", cliA.style);
2499 ok(cliA.cbClsExtra == 0, "got %d\n", cliA.cbClsExtra);
2500 ok(cliA.cbWndExtra == sizeof(LONG_PTR), "got %d\n", cliA.cbWndExtra);
2501 ok(cliA.lpszMenuName == 0, "got %s\n", cliA.lpszMenuName);
2503 DestroyWindow(hwnd);
2505 /* set extra bytes */
2506 hwnd = pSHCreateWorkerWindowA(0, NULL, 0, 0, 0, 0xdeadbeef);
2507 ok(hwnd != 0, "expected window\n");
2509 GetClassNameA(hwnd, classA, 20);
2510 ok(lstrcmpA(classA, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA);
2512 ret = GetWindowLongPtrA(hwnd, 0);
2513 ok(ret == 0xdeadbeef, "got %Id\n", ret);
2515 /* test exstyle */
2516 ret = GetWindowLongA(hwnd, GWL_EXSTYLE);
2517 ok(ret == WS_EX_WINDOWEDGE ||
2518 ret == (WS_EX_WINDOWEDGE|WS_EX_LAYOUTRTL) /* systems with RTL locale */, "0x%08Ix\n", ret);
2520 DestroyWindow(hwnd);
2522 hwnd = pSHCreateWorkerWindowA(0, NULL, WS_EX_TOOLWINDOW, 0, 0, 0);
2523 ret = GetWindowLongA(hwnd, GWL_EXSTYLE);
2524 ok(ret == (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW) ||
2525 ret == (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW|WS_EX_LAYOUTRTL) /* systems with RTL locale */, "0x%08Ix\n", ret);
2526 DestroyWindow(hwnd);
2529 static HRESULT WINAPI SF_QueryInterface(IShellFolder *iface,
2530 REFIID riid, void **ppv)
2532 /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */
2533 ok(!IsEqualGUID(&IID_IShellFolder, riid),
2534 "Unexpected QI for IShellFolder\n");
2535 return E_NOINTERFACE;
2538 static ULONG WINAPI SF_AddRef(IShellFolder *iface)
2540 return 2;
2543 static ULONG WINAPI SF_Release(IShellFolder *iface)
2545 return 1;
2548 static HRESULT WINAPI SF_ParseDisplayName(IShellFolder *iface,
2549 HWND owner, LPBC reserved, LPOLESTR displayName, ULONG *eaten,
2550 LPITEMIDLIST *idl, ULONG *attr)
2552 ok(0, "Didn't expect ParseDisplayName\n");
2553 return E_NOTIMPL;
2556 static HRESULT WINAPI SF_EnumObjects(IShellFolder *iface,
2557 HWND owner, SHCONTF flags, IEnumIDList **enm)
2559 *enm = (IEnumIDList*)0xcafebabe;
2560 return S_OK;
2563 static HRESULT WINAPI SF_BindToObject(IShellFolder *iface,
2564 LPCITEMIDLIST idl, LPBC reserved, REFIID riid, void **obj)
2566 ok(0, "Didn't expect BindToObject\n");
2567 return E_NOTIMPL;
2570 static HRESULT WINAPI SF_BindToStorage(IShellFolder *iface,
2571 LPCITEMIDLIST idl, LPBC reserved, REFIID riid, void **obj)
2573 ok(0, "Didn't expect BindToStorage\n");
2574 return E_NOTIMPL;
2577 static HRESULT WINAPI SF_CompareIDs(IShellFolder *iface,
2578 LPARAM lparam, LPCITEMIDLIST idl1, LPCITEMIDLIST idl2)
2580 ok(0, "Didn't expect CompareIDs\n");
2581 return E_NOTIMPL;
2584 static HRESULT WINAPI SF_CreateViewObject(IShellFolder *iface,
2585 HWND owner, REFIID riid, void **out)
2587 ok(0, "Didn't expect CreateViewObject\n");
2588 return E_NOTIMPL;
2591 static HRESULT WINAPI SF_GetAttributesOf(IShellFolder *iface,
2592 UINT cidl, LPCITEMIDLIST *idl, SFGAOF *inOut)
2594 ok(0, "Didn't expect GetAttributesOf\n");
2595 return E_NOTIMPL;
2598 static HRESULT WINAPI SF_GetUIObjectOf(IShellFolder *iface,
2599 HWND owner, UINT cidl, LPCITEMIDLIST *idls, REFIID riid, UINT *inOut,
2600 void **out)
2602 ok(0, "Didn't expect GetUIObjectOf\n");
2603 return E_NOTIMPL;
2606 static HRESULT WINAPI SF_GetDisplayNameOf(IShellFolder *iface,
2607 LPCITEMIDLIST idl, SHGDNF flags, STRRET *name)
2609 ok(0, "Didn't expect GetDisplayNameOf\n");
2610 return E_NOTIMPL;
2613 static HRESULT WINAPI SF_SetNameOf(IShellFolder *iface,
2614 HWND hwnd, LPCITEMIDLIST idl, LPCOLESTR name, SHGDNF flags,
2615 LPITEMIDLIST *idlOut)
2617 ok(0, "Didn't expect SetNameOf\n");
2618 return E_NOTIMPL;
2621 static IShellFolderVtbl ShellFolderVtbl = {
2622 SF_QueryInterface,
2623 SF_AddRef,
2624 SF_Release,
2625 SF_ParseDisplayName,
2626 SF_EnumObjects,
2627 SF_BindToObject,
2628 SF_BindToStorage,
2629 SF_CompareIDs,
2630 SF_CreateViewObject,
2631 SF_GetAttributesOf,
2632 SF_GetUIObjectOf,
2633 SF_GetDisplayNameOf,
2634 SF_SetNameOf
2637 static IShellFolder ShellFolder = { &ShellFolderVtbl };
2639 static void test_SHIShellFolder_EnumObjects(void)
2641 IEnumIDList *enm;
2642 HRESULT hres;
2643 IShellFolder *folder;
2645 if(!pSHIShellFolder_EnumObjects){ /* win7 and later */
2646 win_skip("SHIShellFolder_EnumObjects not available\n");
2647 return;
2650 if(0){
2651 /* NULL object crashes on Windows */
2652 pSHIShellFolder_EnumObjects(NULL, NULL, 0, NULL);
2655 /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */
2656 enm = (IEnumIDList*)0xdeadbeef;
2657 hres = pSHIShellFolder_EnumObjects(&ShellFolder, NULL, 0, &enm);
2658 ok(hres == S_OK, "SHIShellFolder_EnumObjects failed: 0x%08lx\n", hres);
2659 ok(enm == (IEnumIDList*)0xcafebabe, "Didn't get expected enumerator location, instead: %p\n", enm);
2661 /* SHIShellFolder_EnumObjects isn't strict about the IShellFolder object */
2662 hres = SHGetDesktopFolder(&folder);
2663 ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08lx\n", hres);
2665 enm = NULL;
2666 hres = pSHIShellFolder_EnumObjects(folder, NULL, 0, &enm);
2667 ok(hres == S_OK, "SHIShellFolder_EnumObjects failed: 0x%08lx\n", hres);
2668 ok(enm != NULL, "Didn't get an enumerator\n");
2669 if(enm)
2670 IEnumIDList_Release(enm);
2672 IShellFolder_Release(folder);
2675 static BOOL write_inifile(LPCWSTR filename)
2677 DWORD written;
2678 HANDLE file;
2680 static const char data[] =
2681 "[TestApp]\r\n"
2682 "AKey=1\r\n"
2683 "AnotherKey=asdf\r\n";
2685 file = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
2686 if(file == INVALID_HANDLE_VALUE) {
2687 win_skip("failed to create ini file at %s\n", wine_dbgstr_w(filename));
2688 return FALSE;
2691 WriteFile(file, data, sizeof(data), &written, NULL);
2693 CloseHandle(file);
2695 return TRUE;
2698 #define verify_inifile(f, e) r_verify_inifile(__LINE__, f, e)
2699 static void r_verify_inifile(unsigned l, LPCWSTR filename, LPCSTR exp)
2701 HANDLE file;
2702 CHAR buf[1024];
2703 DWORD read;
2705 file = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
2707 if(file == INVALID_HANDLE_VALUE)
2708 return;
2710 ReadFile(file, buf, sizeof(buf) * sizeof(CHAR), &read, NULL);
2711 buf[read] = '\0';
2713 CloseHandle(file);
2715 ok_(__FILE__,l)(!strcmp(buf, exp), "Expected:\n%s\nGot:\n%s\n", exp,
2716 buf);
2719 static void test_SHGetIniString(void)
2721 DWORD ret;
2722 WCHAR out[64] = {0};
2724 static const WCHAR TestAppW[] = {'T','e','s','t','A','p','p',0};
2725 static const WCHAR AKeyW[] = {'A','K','e','y',0};
2726 static const WCHAR AnotherKeyW[] = {'A','n','o','t','h','e','r','K','e','y',0};
2727 static const WCHAR JunkKeyW[] = {'J','u','n','k','K','e','y',0};
2728 static const WCHAR testpathW[] = {'C',':','\\','t','e','s','t','.','i','n','i',0};
2729 WCHAR pathW[MAX_PATH];
2731 lstrcpyW(pathW, testpathW);
2733 if (!write_inifile(pathW))
2734 return;
2736 if(0){
2737 /* these crash on Windows */
2738 pSHGetIniStringW(NULL, NULL, NULL, 0, NULL);
2739 pSHGetIniStringW(NULL, AKeyW, out, ARRAY_SIZE(out), pathW);
2740 pSHGetIniStringW(TestAppW, AKeyW, NULL, ARRAY_SIZE(out), pathW);
2743 ret = pSHGetIniStringW(TestAppW, AKeyW, out, 0, pathW);
2744 ok(ret == 0, "SHGetIniStringW should have given 0, instead: %ld\n", ret);
2746 /* valid arguments */
2747 out[0] = 0;
2748 SetLastError(0xdeadbeef);
2749 ret = pSHGetIniStringW(TestAppW, NULL, out, ARRAY_SIZE(out), pathW);
2750 ok(ret == 4, "SHGetIniStringW should have given 4, instead: %ld\n", ret);
2751 ok(!lstrcmpW(out, AKeyW), "Expected %s, got: %s, %ld\n",
2752 wine_dbgstr_w(AKeyW), wine_dbgstr_w(out), GetLastError());
2754 ret = pSHGetIniStringW(TestAppW, AKeyW, out, ARRAY_SIZE(out), pathW);
2755 ok(ret == 1, "SHGetIniStringW should have given 1, instead: %ld\n", ret);
2756 ok(!lstrcmpW(out, L"1"), "Expected L\"1\", got: %s\n", wine_dbgstr_w(out));
2758 ret = pSHGetIniStringW(TestAppW, AnotherKeyW, out, ARRAY_SIZE(out), pathW);
2759 ok(ret == 4, "SHGetIniStringW should have given 4, instead: %ld\n", ret);
2760 ok(!lstrcmpW(out, L"asdf"), "Expected L\"asdf\", got: %s\n", wine_dbgstr_w(out));
2762 out[0] = 1;
2763 ret = pSHGetIniStringW(TestAppW, JunkKeyW, out, ARRAY_SIZE(out), pathW);
2764 ok(ret == 0, "SHGetIniStringW should have given 0, instead: %ld\n", ret);
2765 ok(*out == 0, "Expected L\"\", got: %s\n", wine_dbgstr_w(out));
2767 DeleteFileW(pathW);
2770 static void test_SHSetIniString(void)
2772 BOOL ret;
2774 static const WCHAR TestAppW[] = {'T','e','s','t','A','p','p',0};
2775 static const WCHAR AnotherAppW[] = {'A','n','o','t','h','e','r','A','p','p',0};
2776 static const WCHAR TestIniW[] = {'C',':','\\','t','e','s','t','.','i','n','i',0};
2777 static const WCHAR AKeyW[] = {'A','K','e','y',0};
2778 static const WCHAR NewKeyW[] = {'N','e','w','K','e','y',0};
2779 static const WCHAR AValueW[] = {'A','V','a','l','u','e',0};
2781 if (!write_inifile(TestIniW))
2782 return;
2784 ret = pSHSetIniStringW(TestAppW, AKeyW, AValueW, TestIniW);
2785 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2786 todo_wine /* wine sticks an extra \r\n at the end of the file */
2787 verify_inifile(TestIniW, "[TestApp]\r\nAKey=AValue\r\nAnotherKey=asdf\r\n");
2789 ret = pSHSetIniStringW(TestAppW, AKeyW, NULL, TestIniW);
2790 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2791 verify_inifile(TestIniW, "[TestApp]\r\nAnotherKey=asdf\r\n");
2793 ret = pSHSetIniStringW(AnotherAppW, NewKeyW, AValueW, TestIniW);
2794 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2795 verify_inifile(TestIniW, "[TestApp]\r\nAnotherKey=asdf\r\n[AnotherApp]\r\nNewKey=AValue\r\n");
2797 ret = pSHSetIniStringW(TestAppW, NULL, AValueW, TestIniW);
2798 ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
2799 verify_inifile(TestIniW, "[AnotherApp]\r\nNewKey=AValue\r\n");
2801 DeleteFileW(TestIniW);
2804 enum _shellkey_flags {
2805 SHKEY_Root_HKCU = 0x1,
2806 SHKEY_Root_HKLM = 0x2,
2807 SHKEY_Key_Explorer = 0x00,
2808 SHKEY_Key_Shell = 0x10,
2809 SHKEY_Key_ShellNoRoam = 0x20,
2810 SHKEY_Key_Classes = 0x30,
2811 SHKEY_Subkey_Default = 0x0000,
2812 SHKEY_Subkey_ResourceName = 0x1000,
2813 SHKEY_Subkey_Handlers = 0x2000,
2814 SHKEY_Subkey_Associations = 0x3000,
2815 SHKEY_Subkey_Volatile = 0x4000,
2816 SHKEY_Subkey_MUICache = 0x5000,
2817 SHKEY_Subkey_FileExts = 0x6000
2820 static void test_SHGetShellKey(void)
2822 static const WCHAR ShellFoldersW[] = { 'S','h','e','l','l',' ','F','o','l','d','e','r','s',0 };
2823 static const WCHAR WineTestW[] = { 'W','i','n','e','T','e','s','t',0 };
2825 DWORD *alloc_data, data, size;
2826 HKEY hkey;
2827 HRESULT hres;
2829 /* Vista+ limits SHKEY enumeration values */
2830 SetLastError(0xdeadbeef);
2831 hkey = pSHGetShellKey(SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2832 if (hkey)
2834 /* Tests not working on Vista+ */
2835 RegCloseKey(hkey);
2837 hkey = pSHGetShellKey(SHKEY_Root_HKLM|SHKEY_Key_Classes, NULL, FALSE);
2838 ok(hkey != NULL, "hkey = NULL\n");
2839 RegCloseKey(hkey);
2842 hkey = pSHGetShellKey(SHKEY_Root_HKCU|SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2843 ok(hkey != NULL, "hkey = NULL\n");
2844 RegCloseKey(hkey);
2846 hkey = pSHGetShellKey(SHKEY_Root_HKLM|SHKEY_Key_Explorer, ShellFoldersW, FALSE);
2847 ok(hkey != NULL, "hkey = NULL\n");
2848 RegCloseKey(hkey);
2850 hkey = pSHGetShellKey(SHKEY_Root_HKLM, WineTestW, FALSE);
2851 ok(hkey == NULL, "hkey != NULL\n");
2853 hkey = pSHGetShellKey(SHKEY_Root_HKLM, NULL, FALSE);
2854 ok(hkey != NULL, "Can't open key\n");
2855 ok(SUCCEEDED(RegDeleteKeyW(hkey, WineTestW)), "Can't delete key\n");
2856 RegCloseKey(hkey);
2858 hkey = pSHGetShellKey(SHKEY_Root_HKLM, WineTestW, TRUE);
2859 if (!hkey && GetLastError() == ERROR_ACCESS_DENIED)
2861 skip("Not authorized to create keys\n");
2862 return;
2864 ok(hkey != NULL, "Can't create key\n");
2865 RegCloseKey(hkey);
2867 size = sizeof(data);
2868 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
2869 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %lx\n", hres);
2871 data = 1234;
2872 hres = pSKSetValueW(SHKEY_Root_HKLM, WineTestW, NULL, REG_DWORD, &data, sizeof(DWORD));
2873 ok(hres == S_OK, "hres = %lx\n", hres);
2875 size = 1;
2876 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, NULL, &size);
2877 ok(hres == S_OK, "hres = %lx\n", hres);
2878 ok(size == sizeof(DWORD), "size = %ld\n", size);
2880 data = 0xdeadbeef;
2881 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
2882 ok(hres == S_OK, "hres = %lx\n", hres);
2883 ok(size == sizeof(DWORD), "size = %ld\n", size);
2884 ok(data == 1234, "data = %ld\n", data);
2886 hres = pSKAllocValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, (void**)&alloc_data, &size);
2887 ok(hres == S_OK, "hres= %lx\n", hres);
2888 ok(size == sizeof(DWORD), "size = %ld\n", size);
2889 if (SUCCEEDED(hres))
2891 ok(*alloc_data == 1234, "*alloc_data = %ld\n", *alloc_data);
2892 LocalFree(alloc_data);
2895 hres = pSKDeleteValueW(SHKEY_Root_HKLM, WineTestW, NULL);
2896 ok(hres == S_OK, "hres = %lx\n", hres);
2898 hres = pSKDeleteValueW(SHKEY_Root_HKLM, WineTestW, NULL);
2899 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %lx\n", hres);
2901 hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
2902 ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %lx\n", hres);
2904 hkey = pSHGetShellKey(SHKEY_Root_HKLM, NULL, FALSE);
2905 ok(hkey != NULL, "Can't create key\n");
2906 ok(SUCCEEDED(RegDeleteKeyW(hkey, WineTestW)), "Can't delete key\n");
2907 RegCloseKey(hkey);
2910 static void init_pointers(void)
2912 #define MAKEFUNC(f, ord) (p##f = (void*)GetProcAddress(hShlwapi, (LPSTR)(ord)))
2913 MAKEFUNC(SHAllocShared, 7);
2914 MAKEFUNC(SHLockShared, 8);
2915 MAKEFUNC(SHUnlockShared, 9);
2916 MAKEFUNC(SHFreeShared, 10);
2917 MAKEFUNC(SHMapHandle, 11);
2918 MAKEFUNC(GetAcceptLanguagesA, 14);
2919 MAKEFUNC(SHSetWindowBits, 165);
2920 MAKEFUNC(SHSetParentHwnd, 167);
2921 MAKEFUNC(ConnectToConnectionPoint, 168);
2922 MAKEFUNC(IUnknown_GetClassID, 175);
2923 MAKEFUNC(SHSearchMapInt, 198);
2924 MAKEFUNC(SHCreateWorkerWindowA, 257);
2925 MAKEFUNC(GUIDFromStringA, 269);
2926 MAKEFUNC(SHPackDispParams, 282);
2927 MAKEFUNC(IConnectionPoint_InvokeWithCancel, 283);
2928 MAKEFUNC(IConnectionPoint_SimpleInvoke, 284);
2929 MAKEFUNC(SHGetIniStringW, 294);
2930 MAKEFUNC(SHSetIniStringW, 295);
2931 MAKEFUNC(SHFormatDateTimeA, 353);
2932 MAKEFUNC(SHFormatDateTimeW, 354);
2933 MAKEFUNC(SHIShellFolder_EnumObjects, 404);
2934 MAKEFUNC(GetShellSecurityDescriptor, 475);
2935 MAKEFUNC(SHGetObjectCompatFlags, 476);
2936 MAKEFUNC(IUnknown_QueryServiceExec, 484);
2937 MAKEFUNC(SHGetShellKey, 491);
2938 MAKEFUNC(SHPropertyBag_ReadLONG, 496);
2939 MAKEFUNC(IUnknown_ProfferService, 514);
2940 MAKEFUNC(SKGetValueW, 516);
2941 MAKEFUNC(SKSetValueW, 517);
2942 MAKEFUNC(SKDeleteValueW, 518);
2943 MAKEFUNC(SKAllocValueW, 519);
2944 #undef MAKEFUNC
2946 pDllGetVersion = (void*)GetProcAddress(hShlwapi, "DllGetVersion");
2949 static void test_SHSetParentHwnd(void)
2951 HWND hwnd, hwnd2, ret;
2952 DWORD style;
2954 hwnd = CreateWindowA("Button", "", WS_VISIBLE, 0, 0, 10, 10, NULL, NULL, NULL, NULL);
2955 ok(hwnd != NULL, "got %p\n", hwnd);
2957 hwnd2 = CreateWindowA("Button", "", WS_VISIBLE | WS_CHILD, 0, 0, 10, 10, hwnd, NULL, NULL, NULL);
2958 ok(hwnd2 != NULL, "got %p\n", hwnd2);
2960 /* null params */
2961 ret = pSHSetParentHwnd(NULL, NULL);
2962 ok(ret == NULL, "got %p\n", ret);
2964 /* set to no parent while already no parent present */
2965 ret = GetParent(hwnd);
2966 ok(ret == NULL, "got %p\n", ret);
2967 style = GetWindowLongA(hwnd, GWL_STYLE);
2968 ok((style & (WS_POPUP|WS_CHILD)) == 0, "got style 0x%08lx\n", style);
2969 ret = pSHSetParentHwnd(hwnd, NULL);
2970 ok(ret == NULL, "got %p\n", ret);
2971 style = GetWindowLongA(hwnd, GWL_STYLE);
2972 ok((style & (WS_POPUP|WS_CHILD)) == 0, "got style 0x%08lx\n", style);
2974 /* reset to null parent from not null */
2975 ret = GetParent(hwnd2);
2976 ok(ret == hwnd, "got %p\n", ret);
2977 style = GetWindowLongA(hwnd2, GWL_STYLE);
2978 ok((style & (WS_POPUP|WS_CHILD)) == WS_CHILD, "got style 0x%08lx\n", style);
2979 ret = pSHSetParentHwnd(hwnd2, NULL);
2980 ok(ret == NULL, "got %p\n", ret);
2981 style = GetWindowLongA(hwnd2, GWL_STYLE);
2982 ok((style & (WS_POPUP|WS_CHILD)) == WS_POPUP, "got style 0x%08lx\n", style);
2983 ret = GetParent(hwnd2);
2984 ok(ret == NULL, "got %p\n", ret);
2986 /* set parent back */
2987 style = GetWindowLongA(hwnd2, GWL_STYLE);
2988 SetWindowLongA(hwnd2, GWL_STYLE, style & ~(WS_CHILD|WS_POPUP));
2989 style = GetWindowLongA(hwnd2, GWL_STYLE);
2990 ok((style & (WS_CHILD|WS_POPUP)) == 0, "got 0x%08lx\n", style);
2992 ret = pSHSetParentHwnd(hwnd2, hwnd);
2993 todo_wine ok(ret == NULL, "got %p\n", ret);
2995 style = GetWindowLongA(hwnd2, GWL_STYLE);
2996 ok((style & (WS_POPUP|WS_CHILD)) == WS_CHILD, "got style 0x%08lx\n", style);
2997 ret = GetParent(hwnd2);
2998 ok(ret == hwnd, "got %p\n", ret);
3000 /* try to set same parent again */
3001 /* with WS_POPUP */
3002 style = GetWindowLongA(hwnd2, GWL_STYLE);
3003 SetWindowLongA(hwnd2, GWL_STYLE, style | WS_POPUP);
3004 ret = pSHSetParentHwnd(hwnd2, hwnd);
3005 todo_wine ok(ret == NULL, "got %p\n", ret);
3006 style = GetWindowLongA(hwnd2, GWL_STYLE);
3007 ok((style & (WS_CHILD|WS_POPUP)) == WS_CHILD, "got 0x%08lx\n", style);
3008 ret = GetParent(hwnd2);
3009 ok(ret == hwnd, "got %p\n", ret);
3011 /* without WS_POPUP */
3012 style = GetWindowLongA(hwnd2, GWL_STYLE);
3013 SetWindowLongA(hwnd2, GWL_STYLE, style | ~WS_POPUP);
3014 ret = pSHSetParentHwnd(hwnd2, hwnd);
3015 todo_wine ok(ret == hwnd, "got %p\n", ret);
3016 style = GetWindowLongA(hwnd2, GWL_STYLE);
3017 ok((style & (WS_CHILD|WS_POPUP)) == WS_CHILD, "got 0x%08lx\n", style);
3018 ret = GetParent(hwnd2);
3019 ok(ret == hwnd, "got %p\n", ret);
3021 DestroyWindow(hwnd);
3022 DestroyWindow(hwnd2);
3025 static HRESULT WINAPI testpersist_QI(IPersist *iface, REFIID riid, void **obj)
3027 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPersist)) {
3028 *obj = iface;
3029 IPersist_AddRef(iface);
3030 return S_OK;
3033 *obj = NULL;
3034 return E_NOINTERFACE;
3037 static HRESULT WINAPI testpersist_QI2(IPersist *iface, REFIID riid, void **obj)
3039 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPersistFolder)) {
3040 *obj = iface;
3041 IPersist_AddRef(iface);
3042 return S_OK;
3045 *obj = NULL;
3046 return E_NOINTERFACE;
3049 static ULONG WINAPI testpersist_AddRef(IPersist *iface)
3051 return 2;
3054 static ULONG WINAPI testpersist_Release(IPersist *iface)
3056 return 1;
3059 static HRESULT WINAPI testpersist_GetClassID(IPersist *iface, CLSID *clsid)
3061 memset(clsid, 0xab, sizeof(*clsid));
3062 return 0x8fff2222;
3065 static IPersistVtbl testpersistvtbl = {
3066 testpersist_QI,
3067 testpersist_AddRef,
3068 testpersist_Release,
3069 testpersist_GetClassID
3072 static IPersistVtbl testpersist2vtbl = {
3073 testpersist_QI2,
3074 testpersist_AddRef,
3075 testpersist_Release,
3076 testpersist_GetClassID
3079 static IPersist testpersist = { &testpersistvtbl };
3080 static IPersist testpersist2 = { &testpersist2vtbl };
3082 static void test_IUnknown_GetClassID(void)
3084 CLSID clsid, clsid2, clsid3;
3085 HRESULT hr;
3087 if (0) /* crashes on native systems */
3088 hr = pIUnknown_GetClassID(NULL, NULL);
3090 memset(&clsid, 0xcc, sizeof(clsid));
3091 memset(&clsid3, 0xcc, sizeof(clsid3));
3092 hr = pIUnknown_GetClassID(NULL, &clsid);
3093 ok(hr == E_FAIL, "got 0x%08lx\n", hr);
3094 ok(IsEqualCLSID(&clsid, &CLSID_NULL) || broken(IsEqualCLSID(&clsid, &clsid3)) /* win2k, winxp, win2k3 */,
3095 "got wrong clsid %s\n", wine_dbgstr_guid(&clsid));
3097 memset(&clsid, 0xcc, sizeof(clsid));
3098 memset(&clsid2, 0xab, sizeof(clsid2));
3099 hr = pIUnknown_GetClassID((IUnknown*)&testpersist, &clsid);
3100 ok(hr == 0x8fff2222, "got 0x%08lx\n", hr);
3101 ok(IsEqualCLSID(&clsid, &clsid2) || broken(IsEqualCLSID(&clsid, &clsid3)) /* win2k3 */,
3102 "got wrong clsid %s\n", wine_dbgstr_guid(&clsid));
3104 /* IPersistFolder is also supported */
3105 memset(&clsid, 0xcc, sizeof(clsid));
3106 memset(&clsid2, 0xab, sizeof(clsid2));
3107 memset(&clsid3, 0xcc, sizeof(clsid3));
3108 hr = pIUnknown_GetClassID((IUnknown*)&testpersist2, &clsid);
3109 ok(hr == 0x8fff2222, "got 0x%08lx\n", hr);
3110 ok(IsEqualCLSID(&clsid, &clsid2) || broken(IsEqualCLSID(&clsid, &clsid3)) /* win2k3 */,
3111 "got wrong clsid %s\n", wine_dbgstr_guid(&clsid));
3114 static void test_DllGetVersion(void)
3116 HRESULT hr;
3118 hr = pDllGetVersion(NULL);
3119 ok(hr == E_INVALIDARG, "got 0x%08lx\n", hr);
3122 START_TEST(ordinal)
3124 SYSTEMTIME st;
3125 static const SYSTEMTIME february = {2023, 2, 2, 14, 12, 0, 0, 0};
3126 char **argv;
3127 int argc;
3129 hShlwapi = GetModuleHandleA("shlwapi.dll");
3131 init_pointers();
3133 argc = winetest_get_mainargs(&argv);
3134 if (argc >= 4)
3136 DWORD procid;
3137 HANDLE hmem;
3138 sscanf(argv[2], "%ld", &procid);
3139 sscanf(argv[3], "%p", &hmem);
3140 test_alloc_shared_remote(procid, hmem);
3141 return;
3144 test_GetAcceptLanguagesA();
3145 test_SHSearchMapInt();
3146 test_alloc_shared(argc, argv);
3147 test_fdsa();
3148 test_GetShellSecurityDescriptor();
3149 test_SHPackDispParams();
3150 test_IConnectionPoint();
3151 test_SHPropertyBag_ReadLONG();
3152 test_SHSetWindowBits();
3154 GetLocalTime(&st);
3155 test_SHFormatDateTimeA(&st);
3156 /* Test how the locale and code page interact for date formatting by
3157 * repeating the tests with a February date which in French contains an
3158 * e-acute that can only be represented in some code pages.
3160 test_SHFormatDateTimeA(&february);
3162 test_SHFormatDateTimeW();
3163 test_SHGetObjectCompatFlags();
3164 test_IUnknown_QueryServiceExec();
3165 test_IUnknown_ProfferService();
3166 test_SHCreateWorkerWindowA();
3167 test_SHIShellFolder_EnumObjects();
3168 test_SHGetIniString();
3169 test_SHSetIniString();
3170 test_SHGetShellKey();
3171 test_SHSetParentHwnd();
3172 test_IUnknown_GetClassID();
3173 test_DllGetVersion();