dinput: Clear DIA_APPNOMAP BuildActionMap flag with specific device semantic.
[wine.git] / dlls / shell32 / tests / shelldispatch.c
blob67659f72345575b85d784aa90060be77f7a57772
1 /*
2 * Unit tests for IShellDispatch
4 * Copyright 2010 Alexander Morozov for Etersoft
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define COBJMACROS
22 #define NONAMELESSUNION
23 #define NONAMELESSSTRUCT
25 #include "shldisp.h"
26 #include "shlobj.h"
27 #include "shlwapi.h"
28 #include "winsvc.h"
30 #include "wine/test.h"
32 #include "initguid.h"
34 #define EXPECT_HR(hr,hr_exp) \
35 ok(hr == hr_exp, "got 0x%08lx, expected 0x%08lx\n", hr, hr_exp)
37 #define EXPECT_REF(obj,ref) _expect_ref((IUnknown *)obj, ref, __LINE__)
38 static void _expect_ref(IUnknown *obj, ULONG ref, int line)
40 ULONG rc;
41 IUnknown_AddRef(obj);
42 rc = IUnknown_Release(obj);
43 ok_(__FILE__,line)(rc == ref, "Unexpected refcount %ld, expected %ld\n", rc, ref);
46 static const WCHAR winetestW[] = {'w','i','n','e','t','e','s','t',0};
48 static HRESULT (WINAPI *pSHGetNameFromIDList)(PCIDLIST_ABSOLUTE,SIGDN,PWSTR*);
50 /* Updated Windows 7 has a new IShellDispatch6 in its typelib */
51 DEFINE_GUID(IID_IWin7ShellDispatch6, 0x34936ba1, 0x67ad, 0x4c41, 0x99,0xb8, 0x8c,0x12,0xdf,0xf1,0xe9,0x74);
53 static BSTR a2bstr(const char *str)
55 BSTR ret;
56 int len;
58 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
59 ret = SysAllocStringLen(NULL, len);
60 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
62 return ret;
65 static void variant_set_string(VARIANT *v, const char *s)
67 V_VT(v) = VT_BSTR;
68 V_BSTR(v) = a2bstr(s);
71 static void init_function_pointers(void)
73 HMODULE hshell32;
75 hshell32 = GetModuleHandleA("shell32.dll");
76 pSHGetNameFromIDList = (void*)GetProcAddress(hshell32, "SHGetNameFromIDList");
79 static void test_namespace(void)
81 static const ShellSpecialFolderConstants special_folders[] =
83 ssfDESKTOP,
84 ssfPROGRAMS,
85 ssfCONTROLS,
86 ssfPRINTERS,
87 ssfPERSONAL,
88 ssfFAVORITES,
89 ssfSTARTUP,
90 ssfRECENT,
91 ssfSENDTO,
92 ssfBITBUCKET,
93 ssfSTARTMENU,
94 ssfDESKTOPDIRECTORY,
95 ssfDRIVES,
96 ssfNETWORK,
97 ssfNETHOOD,
98 ssfFONTS,
99 ssfTEMPLATES,
100 ssfCOMMONSTARTMENU,
101 ssfCOMMONPROGRAMS,
102 ssfCOMMONSTARTUP,
103 ssfCOMMONDESKTOPDIR,
104 ssfAPPDATA,
105 ssfPRINTHOOD,
106 ssfLOCALAPPDATA,
107 ssfALTSTARTUP,
108 ssfCOMMONALTSTARTUP,
109 ssfCOMMONFAVORITES,
110 ssfINTERNETCACHE,
111 ssfCOOKIES,
112 ssfHISTORY,
113 ssfCOMMONAPPDATA,
114 ssfWINDOWS,
115 ssfSYSTEM,
116 ssfPROGRAMFILES,
117 ssfMYPICTURES,
118 ssfPROFILE,
119 ssfSYSTEMx86,
120 ssfPROGRAMFILESx86,
123 static const WCHAR backslashW[] = {'\\',0};
124 static const WCHAR clsidW[] = {
125 ':',':','{','6','4','5','F','F','0','4','0','-','5','0','8','1','-',
126 '1','0','1','B','-','9','F','0','8','-',
127 '0','0','A','A','0','0','2','F','9','5','4','E','}',0};
129 static WCHAR tempW[MAX_PATH], curW[MAX_PATH];
130 WCHAR *long_pathW = NULL;
131 HRESULT r;
132 IShellDispatch *sd;
133 Folder *folder;
134 Folder2 *folder2;
135 FolderItem *item;
136 VARIANT var;
137 BSTR title, item_path;
138 IDispatch *disp;
139 int len, i;
141 r = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, &IID_IShellDispatch, (void **)&sd);
142 ok(SUCCEEDED(r), "Failed to create ShellDispatch object: %#lx.\n", r);
144 disp = NULL;
145 r = IShellDispatch_get_Application(sd, &disp);
146 ok(r == S_OK, "Failed to get application pointer, hr %#lx.\n", r);
147 ok(disp == (IDispatch *)sd, "Unexpected application pointer %p.\n", disp);
148 IDispatch_Release(disp);
150 disp = NULL;
151 r = IShellDispatch_get_Parent(sd, &disp);
152 ok(r == S_OK, "Failed to get Shell object parent, hr %#lx.\n", r);
153 ok(disp == (IDispatch *)sd, "Unexpected parent pointer %p.\n", disp);
154 IDispatch_Release(disp);
156 VariantInit(&var);
157 folder = (void*)0xdeadbeef;
158 r = IShellDispatch_NameSpace(sd, var, &folder);
159 ok(r == S_FALSE, "expected S_FALSE, got %08lx\n", r);
160 ok(folder == NULL, "expected NULL, got %p\n", folder);
162 /* test valid folder ids */
163 for (i = 0; i < ARRAY_SIZE(special_folders); i++)
165 V_VT(&var) = VT_I4;
166 V_I4(&var) = special_folders[i];
167 folder = (void*)0xdeadbeef;
168 r = IShellDispatch_NameSpace(sd, var, &folder);
169 if (special_folders[i] == ssfALTSTARTUP || special_folders[i] == ssfCOMMONALTSTARTUP)
170 todo_wine
171 ok(r == S_OK || broken(r == S_FALSE) /* winxp */, "Failed to get folder for index %#x, got %08lx\n", special_folders[i], r);
172 else
173 ok(r == S_OK, "Failed to get folder for index %#x, got %08lx\n", special_folders[i], r);
174 if (folder)
175 Folder_Release(folder);
178 V_VT(&var) = VT_I4;
179 V_I4(&var) = -1;
180 folder = (void *)0xdeadbeef;
181 r = IShellDispatch_NameSpace(sd, var, &folder);
182 ok(r == S_FALSE, "Unexpected hr %#lx.\n", r);
183 ok(folder == NULL, "Unexpected folder instance %p\n", folder);
185 V_VT(&var) = VT_I4;
186 V_I4(&var) = ssfPROGRAMFILES;
187 r = IShellDispatch_NameSpace(sd, var, &folder);
188 ok(r == S_OK, "IShellDispatch::NameSpace failed: %08lx\n", r);
189 if (r == S_OK)
191 static WCHAR path[MAX_PATH];
193 r = SHGetFolderPathW(NULL, CSIDL_PROGRAM_FILES, NULL, SHGFP_TYPE_CURRENT, path);
194 ok(r == S_OK, "Failed to get folder path: %#lx.\n", r);
196 r = Folder_get_Title(folder, &title);
197 ok(r == S_OK, "Folder::get_Title failed: %08lx\n", r);
198 if (r == S_OK)
200 /* On Win2000-2003 title is equal to program files directory name in
201 HKLM\Software\Microsoft\Windows\CurrentVersion\ProgramFilesDir.
202 On newer Windows it seems constant and is not changed
203 if the program files directory name is changed */
204 if (pSHGetNameFromIDList)
206 LPITEMIDLIST pidl;
207 PWSTR name;
209 r = SHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidl);
210 ok(r == S_OK, "SHGetSpecialFolderLocation failed: %08lx\n", r);
211 r = pSHGetNameFromIDList(pidl, SIGDN_NORMALDISPLAY, &name);
212 ok(r == S_OK, "SHGetNameFromIDList failed: %08lx\n", r);
213 ok(!lstrcmpW(title, name), "expected %s, got %s\n", wine_dbgstr_w(name), wine_dbgstr_w(title));
214 CoTaskMemFree(name);
215 CoTaskMemFree(pidl);
217 else
219 WCHAR *p;
221 p = path + lstrlenW(path);
222 while (path < p && *(p - 1) != '\\')
223 p--;
224 ok(!lstrcmpiW(title, p), "expected %s, got %s\n",
225 wine_dbgstr_w(p), wine_dbgstr_w(title));
227 SysFreeString(title);
229 r = Folder_QueryInterface(folder, &IID_Folder2, (LPVOID*)&folder2);
230 ok(r == S_OK, "Folder::QueryInterface failed: %08lx\n", r);
231 if (r == S_OK)
233 r = Folder2_get_Self(folder2, &item);
234 ok(r == S_OK, "Folder::get_Self failed: %08lx\n", r);
235 if (r == S_OK)
237 r = FolderItem_get_Path(item, &item_path);
238 ok(r == S_OK, "FolderItem::get_Path failed: %08lx\n", r);
239 ok(!lstrcmpiW(item_path, path), "expected %s, got %s\n", wine_dbgstr_w(path), wine_dbgstr_w(item_path));
240 SysFreeString(item_path);
241 FolderItem_Release(item);
243 Folder2_Release(folder2);
245 Folder_Release(folder);
248 V_VT(&var) = VT_I4;
249 V_I4(&var) = ssfBITBUCKET;
250 r = IShellDispatch_NameSpace(sd, var, &folder);
251 ok(r == S_OK, "IShellDispatch::NameSpace failed: %08lx\n", r);
253 r = Folder_QueryInterface(folder, &IID_Folder2, (void **)&folder2);
254 ok(r == S_OK, "Failed to get Folder2 interface: %#lx.\n", r);
255 r = Folder2_get_Self(folder2, &item);
256 ok(r == S_OK, "Folder::get_Self failed: %08lx\n", r);
257 r = FolderItem_get_Path(item, &item_path);
258 ok(r == S_OK, "FolderItem::get_Path failed: %08lx\n", r);
259 /* TODO: we return lowercase GUID here */
260 ok(!lstrcmpiW(item_path, clsidW), "expected %s, got %s\n", wine_dbgstr_w(clsidW), wine_dbgstr_w(item_path));
262 SysFreeString(item_path);
263 FolderItem_Release(item);
264 Folder2_Release(folder2);
265 Folder_Release(folder);
267 GetTempPathW(MAX_PATH, tempW);
268 GetCurrentDirectoryW(MAX_PATH, curW);
269 SetCurrentDirectoryW(tempW);
270 CreateDirectoryW(winetestW, NULL);
271 V_VT(&var) = VT_BSTR;
272 V_BSTR(&var) = SysAllocString(winetestW);
273 r = IShellDispatch_NameSpace(sd, var, &folder);
274 ok(r == S_FALSE, "expected S_FALSE, got %08lx\n", r);
275 SysFreeString(V_BSTR(&var));
277 GetFullPathNameW(winetestW, MAX_PATH, tempW, NULL);
279 len = GetLongPathNameW(tempW, NULL, 0);
280 long_pathW = malloc(len * sizeof(WCHAR));
281 GetLongPathNameW(tempW, long_pathW, len);
283 V_VT(&var) = VT_BSTR;
284 V_BSTR(&var) = SysAllocString(tempW);
285 r = IShellDispatch_NameSpace(sd, var, &folder);
286 ok(r == S_OK, "IShellDispatch::NameSpace failed: %08lx\n", r);
288 disp = (void *)0xdeadbeef;
289 r = Folder_get_Parent(folder, &disp);
290 ok(r == E_NOTIMPL, "Unexpected hr %#lx.\n", r);
291 ok(disp == NULL, "Unexpected parent pointer %p.\n", disp);
293 r = Folder_get_Title(folder, &title);
294 ok(r == S_OK, "Failed to get folder title: %#lx.\n", r);
295 ok(!lstrcmpW(title, winetestW), "Unexpected title: %s\n", wine_dbgstr_w(title));
296 SysFreeString(title);
298 r = Folder_QueryInterface(folder, &IID_Folder2, (void **)&folder2);
299 ok(r == S_OK, "Failed to get Folder2 interface: %#lx.\n", r);
300 r = Folder2_get_Self(folder2, &item);
301 ok(r == S_OK, "Folder::get_Self failed: %08lx\n", r);
302 r = FolderItem_get_Path(item, &item_path);
303 ok(r == S_OK, "Failed to get item path: %#lx.\n", r);
304 ok(!lstrcmpW(item_path, long_pathW), "Unexpected path %s, got %s\n", wine_dbgstr_w(item_path), wine_dbgstr_w(long_pathW));
305 SysFreeString(item_path);
306 FolderItem_Release(item);
307 Folder2_Release(folder2);
309 Folder_Release(folder);
310 VariantClear(&var);
312 len = lstrlenW(tempW);
313 if (len < MAX_PATH - 1)
315 lstrcatW(tempW, backslashW);
316 V_VT(&var) = VT_BSTR;
317 V_BSTR(&var) = SysAllocString(tempW);
318 r = IShellDispatch_NameSpace(sd, var, &folder);
319 ok(r == S_OK, "IShellDispatch::NameSpace failed: %08lx\n", r);
320 if (r == S_OK)
322 r = Folder_get_Title(folder, &title);
323 ok(r == S_OK, "Folder::get_Title failed: %08lx\n", r);
324 if (r == S_OK)
326 ok(!lstrcmpW(title, winetestW), "bad title: %s\n",
327 wine_dbgstr_w(title));
328 SysFreeString(title);
330 r = Folder_QueryInterface(folder, &IID_Folder2, (LPVOID*)&folder2);
331 ok(r == S_OK, "Failed to get Folder2 interface: %#lx.\n", r);
332 if (r == S_OK)
334 r = Folder2_get_Self(folder2, &item);
335 ok(r == S_OK, "Folder::get_Self failed: %08lx\n", r);
336 if (r == S_OK)
338 r = FolderItem_get_Path(item, &item_path);
339 ok(r == S_OK, "FolderItem::get_Path failed: %08lx\n", r);
340 ok(!lstrcmpW(item_path, long_pathW), "Unexpected path %s, got %s\n", wine_dbgstr_w(item_path),
341 wine_dbgstr_w(long_pathW));
342 SysFreeString(item_path);
343 FolderItem_Release(item);
345 Folder2_Release(folder2);
347 Folder_Release(folder);
349 SysFreeString(V_BSTR(&var));
352 free(long_pathW);
353 RemoveDirectoryW(winetestW);
354 SetCurrentDirectoryW(curW);
355 IShellDispatch_Release(sd);
358 static void test_items(void)
360 static const struct
362 char name[32];
363 enum
365 DIRECTORY,
366 EMPTY_FILE,
368 type;
370 file_defs[] =
372 { "00-Myfolder", DIRECTORY },
373 { "01-empty.bin", EMPTY_FILE },
375 WCHAR path[MAX_PATH], cur_dir[MAX_PATH], orig_dir[MAX_PATH];
376 HRESULT r;
377 IShellDispatch *sd = NULL;
378 Folder *folder = NULL;
379 FolderItems *items;
380 FolderItems2 *items2 = NULL;
381 FolderItems3 *items3 = NULL;
382 FolderItem *item = (FolderItem*)0xdeadbeef, *item2;
383 FolderItemVerbs *verbs = (FolderItemVerbs*)0xdeadbeef;
384 VARIANT var, var2, int_index, str_index, str_index2;
385 IDispatch *disp, *disp2;
386 LONG count = -1;
387 IUnknown *unk;
388 HANDLE file;
389 BSTR bstr;
390 char cstr[64];
391 BOOL ret;
392 int i;
394 r = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, &IID_IShellDispatch, (void**)&sd);
395 ok(SUCCEEDED(r), "CoCreateInstance failed: %08lx\n", r);
396 ok(!!sd, "sd is null\n");
398 /* create and enter a temporary directory and a folder object for it */
399 GetTempPathW(MAX_PATH, path);
400 GetCurrentDirectoryW(MAX_PATH, orig_dir);
401 SetCurrentDirectoryW(path);
402 ret = CreateDirectoryW(winetestW, NULL);
403 ok(ret, "CreateDirectory failed: %08lx\n", GetLastError());
404 GetFullPathNameW(winetestW, MAX_PATH, path, NULL);
405 V_VT(&var) = VT_BSTR;
406 V_BSTR(&var) = SysAllocString(path);
408 EXPECT_REF(sd, 1);
409 r = IShellDispatch_NameSpace(sd, var, &folder);
410 ok(r == S_OK, "IShellDispatch::NameSpace failed: %08lx\n", r);
411 ok(!!folder, "folder is null\n");
412 EXPECT_REF(folder, 1);
413 EXPECT_REF(sd, 1);
415 VariantClear(&var);
416 SetCurrentDirectoryW(winetestW);
417 GetCurrentDirectoryW(MAX_PATH, path);
418 GetLongPathNameW(path, cur_dir, MAX_PATH);
420 /* FolderItems grabs its Folder reference */
421 items = NULL;
422 r = Folder_Items(folder, &items);
423 ok(r == S_OK, "Folder::Items failed: %08lx\n", r);
424 ok(!!items, "items is null\n");
425 EXPECT_REF(folder, 2);
426 EXPECT_REF(items, 1);
428 unk = NULL;
429 r = Folder_Items(folder, (FolderItems **)&unk);
430 ok(r == S_OK, "Folder::Items failed: %08lx\n", r);
431 EXPECT_REF(folder, 3);
432 IUnknown_Release(unk);
433 EXPECT_REF(folder, 2);
435 FolderItems_AddRef(items);
436 EXPECT_REF(folder, 2);
437 FolderItems_Release(items);
439 /* Application property */
440 disp = NULL;
441 EXPECT_REF(sd, 1);
442 r = Folder_get_Application(folder, &disp);
443 ok(r == S_OK, "Failed to get application %#lx.\n", r);
444 ok(disp != (IDispatch *)sd, "Unexpected application pointer\n");
445 EXPECT_REF(sd, 1);
447 disp2 = NULL;
448 r = Folder_get_Application(folder, &disp2);
449 ok(r == S_OK, "Failed to get application %#lx.\n", r);
450 ok(disp2 == disp, "Unexpected application pointer\n");
451 IDispatch_Release(disp2);
453 r = IDispatch_QueryInterface(disp, &IID_IShellDispatch, (void **)&disp2);
454 ok(r == S_OK, "Wrong instance, hr %#lx.\n", r);
455 IDispatch_Release(disp2);
456 IDispatch_Release(disp);
458 if (0) /* crashes on all versions of Windows */
459 r = FolderItems_get_Count(items, NULL);
461 r = FolderItems_get_Count(items, &count);
462 ok(r == S_OK, "FolderItems::get_Count failed: %08lx\n", r);
463 ok(!count, "expected 0 files, got %ld\n", count);
465 V_VT(&var) = VT_I4;
466 V_I4(&var) = 0;
468 if (0) /* crashes on all versions of Windows */
469 r = FolderItems_Item(items, var, NULL);
471 r = FolderItems_Item(items, var, &item);
472 ok(r == S_FALSE, "expected S_FALSE, got %08lx\n", r);
473 ok(!item, "item is not null\n");
475 /* create test files */
476 for (i = 0; i < ARRAY_SIZE(file_defs); i++)
478 switch (file_defs[i].type)
480 case DIRECTORY:
481 r = CreateDirectoryA(file_defs[i].name, NULL);
482 ok(r, "CreateDirectory failed: %08lx\n", GetLastError());
483 PathCombineA(cstr, file_defs[i].name, "foo.txt");
484 file = CreateFileA(cstr, 0, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
485 ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %08lx\n", GetLastError());
486 CloseHandle(file);
487 break;
489 case EMPTY_FILE:
490 file = CreateFileA(file_defs[i].name, 0, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
491 ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %08lx\n", GetLastError());
492 CloseHandle(file);
493 break;
497 /* test that get_Count is not aware of the newly created files */
498 count = -1;
499 r = FolderItems_get_Count(items, &count);
500 ok(r == S_OK, "FolderItems::get_Count failed: %08lx\n", r);
501 ok(!count, "expected 0 files, got %ld\n", count);
503 /* test that the newly created files CAN be retrieved by string index */
504 variant_set_string(&var, file_defs[0].name);
505 item = NULL;
506 r = FolderItems_Item(items, var, &item);
507 ok(r == S_OK, "FolderItems::Item failed: %08lx\n", r);
508 ok(!!item, "item is null\n");
510 disp = (void *)0xdeadbeef;
511 r = FolderItems_get_Parent(items, &disp);
512 ok(r == E_NOTIMPL, "Unexpected hr %#lx.\n", r);
513 ok(disp == NULL, "Unexpected parent pointer %p.\n", disp);
515 r = FolderItem_get_Parent(item, &disp);
516 ok(r == S_OK, "Failed to get parent pointer, hr %#lx.\n", r);
517 ok(disp == (IDispatch *)folder, "Unexpected parent pointer %p.\n", disp);
518 IDispatch_Release(disp);
520 if (item) FolderItem_Release(item);
521 VariantClear(&var);
523 /* recreate the items object */
524 FolderItems_Release(items);
525 items = NULL;
526 r = Folder_Items(folder, &items);
527 ok(r == S_OK, "Folder::Items failed: %08lx\n", r);
528 ok(!!items, "items is null\n");
529 r = FolderItems_QueryInterface(items, &IID_FolderItems2, (void**)&items2);
530 ok(r == S_OK || broken(r == E_NOINTERFACE) /* xp and later */, "FolderItems::QueryInterface failed: %08lx\n", r);
531 if (r == S_OK)
533 ok(!!items2, "items2 is null\n");
534 FolderItems2_Release(items2);
536 r = FolderItems_QueryInterface(items, &IID_FolderItems3, (void**)&items3);
537 ok(r == S_OK, "FolderItems::QueryInterface failed: %08lx\n", r);
538 ok(!!items3, "items3 is null\n");
540 count = -1;
541 r = FolderItems_get_Count(items, &count);
542 ok(r == S_OK, "FolderItems::get_Count failed: %08lx\n", r);
543 ok(count == ARRAY_SIZE(file_defs), "got %ld files\n", count);
545 /* VT_EMPTY */
546 V_VT(&var) = VT_EMPTY;
547 item = (FolderItem*)0xdeadbeef;
548 r = FolderItems_Item(items, var, &item);
549 ok(r == E_NOTIMPL, "expected E_NOTIMPL, got %08lx\n", r);
550 ok(!item, "item is not null\n");
552 /* VT_I2 */
553 V_VT(&var) = VT_I2;
554 V_I2(&var) = 0;
556 EXPECT_REF(folder, 2);
557 EXPECT_REF(items, 2);
558 item = NULL;
559 r = FolderItems_Item(items, var, &item);
560 ok(r == S_OK, "FolderItems::Item failed: %08lx\n", r);
561 ok(!!item, "item is null\n");
562 EXPECT_REF(folder, 3);
563 EXPECT_REF(items, 2);
565 r = Folder_get_Application(folder, &disp);
566 ok(r == S_OK, "Failed to get application pointer %#lx.\n", r);
567 r = FolderItem_get_Application(item, &disp2);
568 ok(r == S_OK, "Failed to get application pointer %#lx.\n", r);
569 ok(disp == disp2, "Unexpected application pointer.\n");
570 IDispatch_Release(disp2);
571 IDispatch_Release(disp);
573 FolderItem_Release(item);
575 /* VT_VARIANT | VT_BYREF */
576 V_VT(&var2) = VT_I2;
577 V_I2(&var2) = 0;
579 V_VT(&var) = VT_BYREF | VT_VARIANT;
580 V_VARIANTREF(&var) = &var2;
582 item = NULL;
583 r = FolderItems_Item(items, var, &item);
584 ok(r == S_OK, "FolderItems::Item failed: %08lx\n", r);
585 ok(!!item, "item is null\n");
586 FolderItem_Release(item);
588 /* VT_I4 */
589 V_VT(&var) = VT_I4;
590 V_I4(&var) = 0;
591 item = NULL;
592 r = FolderItems_Item(items, var, &item);
593 ok(r == S_OK, "FolderItems::Item failed: %08lx\n", r);
594 ok(!!item, "item is null\n");
595 if (item) FolderItem_Release(item);
597 V_I4(&var) = -1;
598 item = (FolderItem*)0xdeadbeef;
599 r = FolderItems_Item(items, var, &item);
600 ok(r == S_FALSE, "expected S_FALSE, got %08lx\n", r);
601 ok(!item, "item is not null\n");
603 V_VT(&var) = VT_ERROR;
604 V_ERROR(&var) = 0;
605 item = NULL;
606 r = FolderItems_Item(items, var, &item);
607 ok(r == S_OK, "expected S_OK, got %08lx\n", r);
608 ok(!!item, "item is null\n");
609 if (item)
611 bstr = NULL;
612 r = FolderItem_get_Path(item, &bstr);
613 ok(r == S_OK, "FolderItem::get_Path failed: %08lx\n", r);
614 ok(!lstrcmpW(bstr, cur_dir),
615 "expected %s, got %s\n", wine_dbgstr_w(cur_dir), wine_dbgstr_w(bstr));
616 SysFreeString(bstr);
617 FolderItem_Release(item);
620 V_VT(&int_index) = VT_I4;
622 /* test the folder item corresponding to each file */
623 for (i = 0; i < ARRAY_SIZE(file_defs); i++)
625 VARIANT_BOOL b;
626 BSTR name;
628 V_I4(&int_index) = i;
629 variant_set_string(&str_index, file_defs[i].name);
631 item = NULL;
632 r = FolderItems_Item(items, int_index, &item);
633 ok(r == S_OK, "file_defs[%d]: FolderItems::Item failed: %08lx\n", i, r);
634 ok(!!item, "file_defs[%d]: item is null\n", i);
636 item2 = NULL;
637 r = FolderItems_Item(items, int_index, &item2);
638 ok(r == S_OK, "file_defs[%d]: FolderItems::Item failed: %08lx\n", i, r);
639 ok(item2 != item, "file_defs[%d]: item and item2 are the same\n", i);
640 FolderItem_Release(item2);
642 bstr = NULL;
643 r = FolderItem_get_Path(item, &bstr);
644 ok(r == S_OK, "file_defs[%d]: FolderItem::get_Path failed: %08lx\n", i, r);
645 PathCombineW(path, cur_dir, V_BSTR(&str_index));
646 ok(!lstrcmpW(bstr, path),
647 "file_defs[%d]: expected %s, got %s\n", i, wine_dbgstr_w(path), wine_dbgstr_w(bstr));
648 SysFreeString(bstr);
650 bstr = a2bstr(file_defs[i].name);
651 r = FolderItem_get_Name(item, &name);
652 ok(r == S_OK, "Failed to get item name, hr %#lx.\n", r);
653 /* Returned display name does not have to strictly match file name, e.g. extension could be omitted. */
654 ok(lstrlenW(name) <= lstrlenW(bstr), "file_defs[%d]: unexpected name length.\n", i);
655 ok(!memcmp(bstr, name, lstrlenW(name) * sizeof(WCHAR)), "file_defs[%d]: unexpected name %s.\n", i, wine_dbgstr_w(name));
656 SysFreeString(name);
657 SysFreeString(bstr);
659 FolderItem_Release(item);
661 item = NULL;
662 r = FolderItems_Item(items, str_index, &item);
663 ok(r == S_OK, "file_defs[%d]: FolderItems::Item failed: %08lx\n", i, r);
664 ok(!!item, "file_defs[%d]: item is null\n", i);
666 bstr = NULL;
667 r = FolderItem_get_Path(item, &bstr);
668 ok(r == S_OK, "file_defs[%d]: FolderItem::get_Path failed: %08lx\n", i, r);
669 PathCombineW(path, cur_dir, V_BSTR(&str_index));
670 ok(!lstrcmpW(bstr, path),
671 "file_defs[%d]: expected %s, got %s\n", i, wine_dbgstr_w(path), wine_dbgstr_w(bstr));
672 SysFreeString(bstr);
674 b = 0xdead;
675 r = FolderItem_get_IsFolder(item, &b);
676 ok(r == S_OK, "Failed to get IsFolder property, %#lx.\n", r);
677 ok(file_defs[i].type == DIRECTORY ? b == VARIANT_TRUE : b == VARIANT_FALSE, "Unexpected prop value %#x.\n", b);
679 FolderItem_Release(item);
681 if (file_defs[i].type == DIRECTORY)
683 /* test that getting an item object for a file in a subdirectory succeeds */
684 PathCombineA(cstr, file_defs[i].name, "foo.txt");
685 variant_set_string(&str_index2, cstr);
686 item2 = NULL;
687 r = FolderItems_Item(items, str_index2, &item2);
688 ok(r == S_OK, "file_defs[%d]: FolderItems::Item failed: %08lx\n", i, r);
689 ok(!!item2, "file_defs[%d]: item is null\n", i);
690 if (item2) FolderItem_Release(item2);
691 VariantClear(&str_index2);
693 /* delete the file in the subdirectory */
694 ret = DeleteFileA(cstr);
695 ok(ret, "file_defs[%d]: DeleteFile failed: %08lx\n", i, GetLastError());
697 /* test that getting an item object via a relative path fails */
698 strcpy(cstr, file_defs[i].name);
699 strcat(cstr, "\\..\\");
700 strcat(cstr, file_defs[i].name);
701 variant_set_string(&str_index2, cstr);
702 item2 = (FolderItem*)0xdeadbeef;
703 r = FolderItems_Item(items, str_index2, &item2);
704 ok(r == S_FALSE, "file_defs[%d]: expected S_FALSE, got %08lx\n", i, r);
705 ok(!item2, "file_defs[%d]: item is not null\n", i);
706 VariantClear(&str_index2);
708 /* remove the directory */
709 ret = RemoveDirectoryA(file_defs[i].name);
710 ok(ret, "file_defs[%d]: RemoveDirectory failed: %08lx\n", i, GetLastError());
712 else
714 ret = DeleteFileA(file_defs[i].name);
715 ok(ret, "file_defs[%d]: DeleteFile failed: %08lx\n", i, GetLastError());
718 /* test that the folder item is still accessible by integer index */
719 item = NULL;
720 r = FolderItems_Item(items, int_index, &item);
721 ok(r == S_OK, "file_defs[%d]: FolderItems::Item failed: %08lx\n", i, r);
722 ok(!!item, "file_defs[%d]: item is null\n", i);
724 bstr = NULL;
725 r = FolderItem_get_Path(item, &bstr);
726 ok(r == S_OK, "file_defs[%d]: FolderItem::get_Path failed: %08lx\n", i, r);
727 PathCombineW(path, cur_dir, V_BSTR(&str_index));
728 ok(!lstrcmpW(bstr, path),
729 "file_defs[%d]: expected %s, got %s\n", i, wine_dbgstr_w(path), wine_dbgstr_w(bstr));
730 SysFreeString(bstr);
732 FolderItem_Release(item);
734 /* test that the folder item is no longer accessible by string index */
735 item = (FolderItem*)0xdeadbeef;
736 r = FolderItems_Item(items, str_index, &item);
737 ok(r == S_FALSE, "file_defs[%d]: expected S_FALSE, got %08lx\n", i, r);
738 ok(!item, "file_defs[%d]: item is not null\n", i);
740 VariantClear(&str_index);
743 /* test that there are only as many folder items as there were files */
744 V_I4(&int_index) = ARRAY_SIZE(file_defs);
745 item = (FolderItem*)0xdeadbeef;
746 r = FolderItems_Item(items, int_index, &item);
747 ok(r == S_FALSE, "expected S_FALSE, got %08lx\n", r);
748 ok(!item, "item is not null\n");
750 if (0) /* crashes on xp */
752 r = FolderItems_get_Application(items, NULL);
753 ok(r == E_INVALIDARG, "expected E_INVALIDARG, got %08lx\n", r);
756 r = FolderItems_get_Application(items, &disp);
757 ok(r == S_OK, "FolderItems::get_Application failed: %08lx\n", r);
759 r = Folder_get_Application(folder, &disp2);
760 ok(r == S_OK, "Failed to get application pointer, hr %#lx.\n", r);
761 ok(disp == disp2, "Unexpected application pointer.\n");
762 IDispatch_Release(disp2);
763 IDispatch_Release(disp);
765 if (0) /* crashes on xp */
767 r = FolderItems_get_Parent(items, NULL);
768 ok(r == E_NOTIMPL, "expected E_NOTIMPL, got %08lx\n", r);
771 disp = (IDispatch*)0xdeadbeef;
772 r = FolderItems_get_Parent(items, &disp);
773 ok(r == E_NOTIMPL, "expected E_NOTIMPL, got %08lx\n", r);
774 ok(!disp, "disp is not null\n");
776 if (0) /* crashes on xp */
778 r = FolderItems__NewEnum(items, NULL);
779 ok(r == E_INVALIDARG, "expected E_INVALIDARG, got %08lx\n", r);
782 r = FolderItems__NewEnum(items, &unk);
783 todo_wine
784 ok(r == S_OK, "FolderItems::_NewEnum failed: %08lx\n", r);
785 todo_wine
786 ok(!!unk, "unk is null\n");
787 if (unk) IUnknown_Release(unk);
789 if (items3)
791 r = FolderItems3_Filter(items3, 0, NULL);
792 todo_wine
793 ok(r == S_OK, "expected S_OK, got %08lx\n", r);
795 if (0) /* crashes on xp */
797 r = FolderItems3_get_Verbs(items3, NULL);
798 ok(r == E_INVALIDARG, "expected E_INVALIDARG, got %08lx\n", r);
801 r = FolderItems3_get_Verbs(items3, &verbs);
802 todo_wine
803 ok(r == S_FALSE, "expected S_FALSE, got %08lx\n", r);
804 ok(!verbs, "verbs is not null\n");
807 /* remove the temporary directory and restore the original working directory */
808 GetTempPathW(MAX_PATH, path);
809 SetCurrentDirectoryW(path);
810 ret = RemoveDirectoryW(winetestW);
811 ok(ret, "RemoveDirectory failed: %08lx\n", GetLastError());
812 SetCurrentDirectoryW(orig_dir);
814 /* test that everything stops working after the directory has been removed */
815 count = -1;
816 r = FolderItems_get_Count(items, &count);
817 ok(r == S_OK, "FolderItems::get_Count failed: %08lx\n", r);
818 ok(!count, "expected 0 files, got %ld\n", count);
820 item = NULL;
821 V_I4(&int_index) = 0;
822 item = (FolderItem*)0xdeadbeef;
823 r = FolderItems_Item(items, int_index, &item);
824 ok(r == S_FALSE, "expected S_FALSE, got %08lx\n", r);
825 ok(!item, "item is not null\n");
827 variant_set_string(&str_index, file_defs[0].name);
828 item = (FolderItem*)0xdeadbeef;
829 r = FolderItems_Item(items, str_index, &item);
830 ok(r == S_FALSE, "expected S_FALSE, got %08lx\n", r);
831 ok(!item, "item is not null\n");
832 VariantClear(&str_index);
834 FolderItems_Release(items);
835 Folder_Release(folder);
836 if (items3) FolderItems3_Release(items3);
837 IShellDispatch_Release(sd);
840 static void test_service(void)
842 static const WCHAR spooler[] = {'S','p','o','o','l','e','r',0};
843 static const WCHAR dummyW[] = {'d','u','m','m','y',0};
844 SERVICE_STATUS_PROCESS status;
845 SC_HANDLE scm, service;
846 IShellDispatch2 *sd;
847 DWORD dummy;
848 HRESULT hr;
849 BSTR name;
850 VARIANT v;
852 hr = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER,
853 &IID_IShellDispatch2, (void**)&sd);
854 if (hr != S_OK)
856 win_skip("IShellDispatch2 not supported\n");
857 return;
860 V_VT(&v) = VT_I2;
861 V_I2(&v) = 10;
862 hr = IShellDispatch2_IsServiceRunning(sd, NULL, &v);
863 ok(V_VT(&v) == VT_BOOL, "got %d\n", V_VT(&v));
864 ok(V_BOOL(&v) == VARIANT_FALSE, "got %d\n", V_BOOL(&v));
865 EXPECT_HR(hr, S_OK);
867 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
868 service = OpenServiceW(scm, spooler, SERVICE_QUERY_STATUS);
869 QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy);
870 CloseServiceHandle(service);
871 CloseServiceHandle(scm);
873 /* service should exist */
874 name = SysAllocString(spooler);
875 V_VT(&v) = VT_I2;
876 hr = IShellDispatch2_IsServiceRunning(sd, name, &v);
877 EXPECT_HR(hr, S_OK);
878 ok(V_VT(&v) == VT_BOOL, "got %d\n", V_VT(&v));
879 if (status.dwCurrentState == SERVICE_RUNNING)
880 ok(V_BOOL(&v) == VARIANT_TRUE, "got %d\n", V_BOOL(&v));
881 else
882 ok(V_BOOL(&v) == VARIANT_FALSE, "got %d\n", V_BOOL(&v));
883 SysFreeString(name);
885 /* service doesn't exist */
886 name = SysAllocString(dummyW);
887 V_VT(&v) = VT_I2;
888 hr = IShellDispatch2_IsServiceRunning(sd, name, &v);
889 EXPECT_HR(hr, S_OK);
890 ok(V_VT(&v) == VT_BOOL, "got %d\n", V_VT(&v));
891 ok(V_BOOL(&v) == VARIANT_FALSE, "got %d\n", V_BOOL(&v));
892 SysFreeString(name);
894 IShellDispatch2_Release(sd);
897 static void test_dispatch_typeinfo(IDispatch *disp, REFIID *riid)
899 ITypeInfo *typeinfo;
900 TYPEATTR *typeattr;
901 UINT count;
902 HRESULT hr;
904 count = 10;
905 hr = IDispatch_GetTypeInfoCount(disp, &count);
906 ok(hr == S_OK, "got 0x%08lx\n", hr);
907 ok(count == 1, "got %u\n", count);
909 hr = IDispatch_GetTypeInfo(disp, 0, LOCALE_SYSTEM_DEFAULT, &typeinfo);
910 ok(hr == S_OK, "got 0x%08lx\n", hr);
912 hr = ITypeInfo_GetTypeAttr(typeinfo, &typeattr);
913 ok(hr == S_OK, "got 0x%08lx\n", hr);
914 while (!IsEqualGUID(*riid, &IID_NULL)) {
915 if (IsEqualGUID(&typeattr->guid, *riid))
916 break;
917 riid++;
919 ok(IsEqualGUID(&typeattr->guid, *riid), "unexpected type guid %s\n", wine_dbgstr_guid(&typeattr->guid));
921 ITypeInfo_ReleaseTypeAttr(typeinfo, typeattr);
922 ITypeInfo_Release(typeinfo);
925 static void test_ShellFolderViewDual(void)
927 static const IID *shelldisp_riids[] = {
928 &IID_IShellDispatch6,
929 &IID_IShellDispatch5,
930 &IID_IShellDispatch4,
931 &IID_IShellDispatch2,
932 &IID_IWin7ShellDispatch6,
933 &IID_NULL
935 IShellFolderViewDual *viewdual;
936 IShellFolder *desktop, *tmpdir;
937 IShellView *view, *view2;
938 IDispatch *disp, *disp2;
939 WCHAR pathW[MAX_PATH];
940 LPITEMIDLIST pidl;
941 HRESULT hr;
943 /* IShellFolderViewDual is not an IShellView extension */
944 hr = SHGetDesktopFolder(&desktop);
945 ok(hr == S_OK, "got 0x%08lx\n", hr);
947 hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
948 ok(hr == S_OK, "got 0x%08lx\n", hr);
950 hr = IShellView_QueryInterface(view, &IID_IShellFolderViewDual, (void**)&viewdual);
951 ok(hr == E_NOINTERFACE, "got 0x%08lx\n", hr);
953 hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IDispatch, (void**)&disp);
954 ok(hr == S_OK, "got 0x%08lx\n", hr);
956 hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IDispatch, (void**)&disp2);
957 ok(hr == S_OK, "got 0x%08lx\n", hr);
958 ok(disp2 == disp, "got %p, %p\n", disp2, disp);
959 IDispatch_Release(disp2);
961 hr = IDispatch_QueryInterface(disp, &IID_IShellFolderViewDual, (void**)&viewdual);
962 ok(hr == S_OK, "got 0x%08lx\n", hr);
963 ok(disp == (IDispatch*)viewdual, "got %p, expected %p\n", viewdual, disp);
965 hr = IShellFolderViewDual_QueryInterface(viewdual, &IID_IShellView, (void**)&view2);
966 ok(hr == E_NOINTERFACE, "got 0x%08lx\n", hr);
968 /* get_Application() */
970 if (0) /* crashes on pre-vista */ {
971 hr = IShellFolderViewDual_get_Application(viewdual, NULL);
972 ok(hr == E_INVALIDARG, "got 0x%08lx\n", hr);
974 hr = IShellFolderViewDual_get_Application(viewdual, &disp2);
975 ok(hr == S_OK, "got 0x%08lx\n", hr);
976 ok(disp2 != (IDispatch*)viewdual, "got %p, %p\n", disp2, viewdual);
977 test_dispatch_typeinfo(disp2, shelldisp_riids);
978 IDispatch_Release(disp2);
980 IShellFolderViewDual_Release(viewdual);
981 IDispatch_Release(disp);
983 disp = (void*)0xdeadbeef;
984 hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IShellFolderViewDual, (void**)&disp);
985 ok(hr == E_NOINTERFACE || broken(hr == E_NOTIMPL) /* win2k */, "got 0x%08lx\n", hr);
986 ok(disp == NULL, "got %p\n", disp);
987 IShellView_Release(view);
989 /* Try with some other folder, that's not a desktop */
990 GetTempPathW(ARRAY_SIZE(pathW), pathW);
991 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, pathW, NULL, &pidl, NULL);
992 ok(hr == S_OK, "got 0x%08lx\n", hr);
994 hr = IShellFolder_BindToObject(desktop, pidl, NULL, &IID_IShellFolder, (void**)&tmpdir);
995 ok(hr == S_OK, "got 0x%08lx\n", hr);
996 CoTaskMemFree(pidl);
998 hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
999 ok(hr == S_OK, "got 0x%08lx\n", hr);
1001 hr = IShellView_QueryInterface(view, &IID_IShellFolderViewDual, (void**)&viewdual);
1002 ok(hr == E_NOINTERFACE, "got 0x%08lx\n", hr);
1004 hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IDispatch, (void**)&disp);
1005 ok(hr == S_OK, "got 0x%08lx\n", hr);
1006 IDispatch_Release(disp);
1007 IShellView_Release(view);
1009 IShellFolder_Release(tmpdir);
1010 IShellFolder_Release(desktop);
1013 static void test_ShellWindows(void)
1015 IShellWindows *shellwindows;
1016 LONG cookie, cookie2, ret;
1017 ITEMIDLIST *pidl;
1018 IDispatch *disp;
1019 VARIANT v, v2;
1020 HRESULT hr;
1021 HWND hwnd;
1023 hr = CoCreateInstance(&CLSID_ShellWindows, NULL, CLSCTX_LOCAL_SERVER,
1024 &IID_IShellWindows, (void**)&shellwindows);
1025 ok(hr == S_OK, "got 0x%08lx\n", hr);
1026 /* TODO: remove when explorer startup with clean prefix is fixed */
1027 if (hr != S_OK)
1028 return;
1030 hr = IShellWindows_Register(shellwindows, NULL, 0, SWC_EXPLORER, NULL);
1031 ok(hr == HRESULT_FROM_WIN32(RPC_X_NULL_REF_POINTER), "got 0x%08lx\n", hr);
1033 hr = IShellWindows_Register(shellwindows, NULL, 0, SWC_EXPLORER, &cookie);
1034 ok(hr == E_POINTER, "got 0x%08lx\n", hr);
1036 hr = IShellWindows_Register(shellwindows, (IDispatch*)shellwindows, 0, SWC_EXPLORER, &cookie);
1037 ok(hr == E_POINTER, "got 0x%08lx\n", hr);
1039 hr = IShellWindows_Register(shellwindows, (IDispatch*)shellwindows, 0, SWC_EXPLORER, &cookie);
1040 ok(hr == E_POINTER, "got 0x%08lx\n", hr);
1042 hwnd = CreateWindowExA(0, "button", "test", BS_CHECKBOX | WS_VISIBLE | WS_POPUP,
1043 0, 0, 50, 14, 0, 0, 0, NULL);
1044 ok(hwnd != NULL, "got %p, error %ld\n", hwnd, GetLastError());
1046 cookie = 0;
1047 hr = IShellWindows_Register(shellwindows, NULL, HandleToLong(hwnd), SWC_EXPLORER, &cookie);
1048 ok(hr == S_OK, "got 0x%08lx\n", hr);
1049 ok(cookie != 0, "got %ld\n", cookie);
1051 cookie2 = 0;
1052 hr = IShellWindows_Register(shellwindows, NULL, HandleToLong(hwnd), SWC_EXPLORER, &cookie2);
1053 ok(hr == S_OK, "got 0x%08lx\n", hr);
1054 ok(cookie2 != 0 && cookie2 != cookie, "got %ld\n", cookie2);
1056 pidl = ILCreateFromPathA("C:\\");
1057 V_VT(&v) = VT_ARRAY | VT_UI1;
1058 V_ARRAY(&v) = SafeArrayCreateVector(VT_UI1, 0, ILGetSize(pidl));
1059 memcpy(V_ARRAY(&v)->pvData, pidl, ILGetSize(pidl));
1061 VariantInit(&v2);
1062 hr = IShellWindows_FindWindowSW(shellwindows, &v, &v2, SWC_EXPLORER, &ret, 0, &disp);
1063 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
1064 ok(!ret, "Got window %#lx.\n", ret);
1065 ok(!disp, "Got IDispatch %p.\n", &disp);
1067 hr = IShellWindows_OnNavigate(shellwindows, 0, &v);
1068 ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
1070 hr = IShellWindows_OnNavigate(shellwindows, cookie, &v);
1071 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1073 hr = IShellWindows_FindWindowSW(shellwindows, &v, &v2, SWC_EXPLORER, &ret, 0, &disp);
1074 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1075 ok(ret == (LONG)(LONG_PTR)hwnd, "Expected %p, got %#lx.\n", hwnd, ret);
1076 ok(!disp, "Got IDispatch %p.\n", &disp);
1078 hr = IShellWindows_Revoke(shellwindows, cookie);
1079 ok(hr == S_OK, "got 0x%08lx\n", hr);
1081 hr = IShellWindows_FindWindowSW(shellwindows, &v, &v2, SWC_EXPLORER, &ret, 0, &disp);
1082 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
1083 ok(!ret, "Got window %#lx.\n", ret);
1084 ok(!disp, "Got IDispatch %p.\n", &disp);
1086 hr = IShellWindows_Revoke(shellwindows, cookie2);
1087 ok(hr == S_OK, "got 0x%08lx\n", hr);
1089 hr = IShellWindows_Revoke(shellwindows, 0);
1090 ok(hr == S_FALSE, "got 0x%08lx\n", hr);
1092 /* we can register ourselves as desktop, but FindWindowSW still returns real desktop window */
1093 cookie = 0;
1094 hr = IShellWindows_Register(shellwindows, NULL, HandleToLong(hwnd), SWC_DESKTOP, &cookie);
1095 ok(hr == S_OK, "got 0x%08lx\n", hr);
1096 ok(cookie != 0, "got %ld\n", cookie);
1098 disp = (void*)0xdeadbeef;
1099 ret = 0xdead;
1100 VariantInit(&v);
1101 hr = IShellWindows_FindWindowSW(shellwindows, &v, &v, SWC_DESKTOP, &ret, SWFO_NEEDDISPATCH, &disp);
1102 ok(hr == S_OK || broken(hr == S_FALSE), "got 0x%08lx\n", hr);
1103 if (hr == S_FALSE) /* winxp and earlier */ {
1104 win_skip("SWC_DESKTOP is not supported, some tests will be skipped.\n");
1105 /* older versions allowed to register SWC_DESKTOP and access it with FindWindowSW */
1106 ok(disp == NULL, "got %p\n", disp);
1107 ok(ret == 0, "got %ld\n", ret);
1109 else {
1110 static const IID *browser_riids[] = {
1111 &IID_IWebBrowser2,
1112 &IID_NULL
1115 static const IID *viewdual_riids[] = {
1116 &IID_IShellFolderViewDual3,
1117 &IID_NULL
1120 IShellFolderViewDual *view;
1121 IShellBrowser *sb, *sb2;
1122 IServiceProvider *sp;
1123 IDispatch *doc, *app;
1124 IWebBrowser2 *wb;
1125 IShellView *sv;
1126 IUnknown *unk;
1128 ok(disp != NULL, "got %p\n", disp);
1129 ok(ret != HandleToUlong(hwnd), "got %ld\n", ret);
1131 /* IDispatch-related tests */
1132 test_dispatch_typeinfo(disp, browser_riids);
1134 /* IWebBrowser2 */
1135 hr = IDispatch_QueryInterface(disp, &IID_IWebBrowser2, (void**)&wb);
1136 ok(hr == S_OK, "got 0x%08lx\n", hr);
1138 hr = IWebBrowser2_Refresh(wb);
1139 todo_wine
1140 ok(hr == S_OK, "got 0x%08lx\n", hr);
1142 hr = IWebBrowser2_get_Application(wb, &app);
1143 ok(hr == S_OK, "got 0x%08lx\n", hr);
1144 ok(disp == app, "got %p, %p\n", app, disp);
1145 IDispatch_Release(app);
1147 hr = IWebBrowser2_get_Document(wb, &doc);
1148 todo_wine
1149 ok(hr == S_OK, "got 0x%08lx\n", hr);
1150 if (hr == S_OK) {
1151 test_dispatch_typeinfo(doc, viewdual_riids);
1153 IWebBrowser2_Release(wb);
1155 /* IServiceProvider */
1156 hr = IDispatch_QueryInterface(disp, &IID_IShellFolderViewDual, (void**)&view);
1157 ok(hr == E_NOINTERFACE, "got 0x%08lx\n", hr);
1159 hr = IDispatch_QueryInterface(disp, &IID_IServiceProvider, (void**)&sp);
1160 ok(hr == S_OK, "got 0x%08lx\n", hr);
1162 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IShellBrowser, (void**)&sb);
1163 ok(hr == S_OK, "got 0x%08lx\n", hr);
1165 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IShellBrowser, (void**)&sb2);
1166 ok(hr == S_OK, "got 0x%08lx\n", hr);
1167 ok(sb == sb2, "got %p, %p\n", sb, sb2);
1169 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IOleWindow, (void**)&unk);
1170 ok(hr == S_OK, "got 0x%08lx\n", hr);
1171 IUnknown_Release(unk);
1173 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IExplorerBrowser, (void**)&unk);
1174 ok(hr == E_NOINTERFACE, "got 0x%08lx\n", hr);
1176 hr = IShellBrowser_QueryInterface(sb, &IID_IExplorerBrowser, (void**)&unk);
1177 ok(hr == E_NOINTERFACE, "got 0x%08lx\n", hr);
1179 hr = IShellBrowser_QueryInterface(sb, &IID_IWebBrowser2, (void**)&unk);
1180 ok(hr == E_NOINTERFACE, "got 0x%08lx\n", hr);
1182 hr = IShellBrowser_QueryInterface(sb, &IID_IDispatch, (void**)&unk);
1183 ok(hr == E_NOINTERFACE, "got 0x%08lx\n", hr);
1185 hr = IShellBrowser_QueryActiveShellView(sb, &sv);
1186 ok(hr == S_OK, "got 0x%08lx\n", hr);
1187 IShellView_Release(sv);
1189 IShellBrowser_Release(sb2);
1190 IShellBrowser_Release(sb);
1192 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IUnknown, (void**)&unk);
1193 ok(hr == S_OK, "got 0x%08lx\n", hr);
1195 hr = IUnknown_QueryInterface(unk, &IID_IShellBrowser, (void**)&sb2);
1196 ok(hr == S_OK, "got 0x%08lx\n", hr);
1197 IShellBrowser_Release(sb2);
1198 IUnknown_Release(unk);
1200 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IShellView, (void**)&sv);
1201 ok(hr == E_NOINTERFACE, "got 0x%08lx\n", hr);
1203 IServiceProvider_Release(sp);
1204 IDispatch_Release(disp);
1207 disp = (void*)0xdeadbeef;
1208 ret = 0xdead;
1209 VariantInit(&v);
1210 hr = IShellWindows_FindWindowSW(shellwindows, &v, &v, SWC_DESKTOP, &ret, 0, &disp);
1211 ok(hr == S_OK || broken(hr == S_FALSE) /* winxp */, "got 0x%08lx\n", hr);
1212 ok(disp == NULL, "got %p\n", disp);
1213 ok(ret != HandleToUlong(hwnd), "got %ld\n", ret);
1215 disp = (void*)0xdeadbeef;
1216 ret = 0xdead;
1217 V_VT(&v) = VT_I4;
1218 V_I4(&v) = cookie;
1219 VariantInit(&v2);
1220 hr = IShellWindows_FindWindowSW(shellwindows, &v, &v2, SWC_BROWSER, &ret, SWFO_COOKIEPASSED, &disp);
1221 todo_wine
1222 ok(hr == S_FALSE, "got 0x%08lx\n", hr);
1223 ok(disp == NULL, "got %p\n", disp);
1224 ok(ret == 0, "got %ld\n", ret);
1226 hr = IShellWindows_Revoke(shellwindows, cookie);
1227 ok(hr == S_OK, "got 0x%08lx\n", hr);
1228 DestroyWindow(hwnd);
1229 IShellWindows_Release(shellwindows);
1232 static void test_ParseName(void)
1234 static const WCHAR cadabraW[] = {'c','a','d','a','b','r','a',0};
1235 WCHAR pathW[MAX_PATH];
1236 IShellDispatch *sd;
1237 FolderItem *item;
1238 Folder *folder;
1239 HRESULT hr;
1240 VARIANT v;
1241 BSTR str;
1243 hr = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER,
1244 &IID_IShellDispatch, (void**)&sd);
1245 ok(hr == S_OK, "got 0x%08lx\n", hr);
1247 GetTempPathW(ARRAY_SIZE(pathW), pathW);
1248 V_VT(&v) = VT_BSTR;
1249 V_BSTR(&v) = SysAllocString(pathW);
1250 hr = IShellDispatch_NameSpace(sd, v, &folder);
1251 ok(hr == S_OK, "got 0x%08lx\n", hr);
1252 VariantClear(&v);
1254 item = (void*)0xdeadbeef;
1255 hr = Folder_ParseName(folder, NULL, &item);
1256 ok(hr == S_FALSE || broken(hr == E_INVALIDARG) /* win2k */, "got 0x%08lx\n", hr);
1257 ok(item == NULL, "got %p\n", item);
1259 /* empty name */
1260 str = SysAllocStringLen(NULL, 0);
1261 item = (void*)0xdeadbeef;
1262 hr = Folder_ParseName(folder, str, &item);
1263 ok(hr == S_FALSE || broken(hr == E_INVALIDARG) /* win2k */, "got 0x%08lx\n", hr);
1264 ok(item == NULL, "got %p\n", item);
1265 SysFreeString(str);
1267 /* path doesn't exist */
1268 str = SysAllocString(cadabraW);
1269 item = (void*)0xdeadbeef;
1270 hr = Folder_ParseName(folder, str, &item);
1271 ok(hr == S_FALSE || broken(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) /* win2k */,
1272 "got 0x%08lx\n", hr);
1273 ok(item == NULL, "got %p\n", item);
1274 SysFreeString(str);
1276 lstrcatW(pathW, cadabraW);
1277 CreateDirectoryW(pathW, NULL);
1279 str = SysAllocString(cadabraW);
1280 item = NULL;
1281 hr = Folder_ParseName(folder, str, &item);
1282 ok(hr == S_OK, "got 0x%08lx\n", hr);
1283 ok(item != NULL, "got %p\n", item);
1284 SysFreeString(str);
1286 hr = FolderItem_get_Path(item, &str);
1287 ok(hr == S_OK, "got 0x%08lx\n", hr);
1288 ok(str[0] != 0, "path %s\n", wine_dbgstr_w(str));
1289 SysFreeString(str);
1291 RemoveDirectoryW(pathW);
1292 FolderItem_Release(item);
1293 Folder_Release(folder);
1294 IShellDispatch_Release(sd);
1297 static void test_Verbs(void)
1299 FolderItemVerbs *verbs, *verbs2;
1300 WCHAR pathW[MAX_PATH];
1301 FolderItemVerb *verb;
1302 IShellDispatch *sd;
1303 FolderItem *item;
1304 Folder2 *folder2;
1305 IDispatch *disp;
1306 Folder *folder;
1307 HRESULT hr;
1308 LONG count, i;
1309 VARIANT v;
1310 BSTR str;
1312 hr = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER,
1313 &IID_IShellDispatch, (void**)&sd);
1314 ok(hr == S_OK, "got 0x%08lx\n", hr);
1316 GetTempPathW(ARRAY_SIZE(pathW), pathW);
1317 V_VT(&v) = VT_BSTR;
1318 V_BSTR(&v) = SysAllocString(pathW);
1319 hr = IShellDispatch_NameSpace(sd, v, &folder);
1320 ok(hr == S_OK, "got 0x%08lx\n", hr);
1321 VariantClear(&v);
1323 hr = Folder_QueryInterface(folder, &IID_Folder2, (void**)&folder2);
1324 ok(hr == S_OK, "got 0x%08lx\n", hr);
1325 Folder_Release(folder);
1327 hr = Folder2_get_Self(folder2, &item);
1328 ok(hr == S_OK, "got 0x%08lx\n", hr);
1329 Folder2_Release(folder2);
1331 if (0) { /* crashes on some systems */
1332 hr = FolderItem_Verbs(item, NULL);
1333 ok(hr == E_INVALIDARG, "got 0x%08lx\n", hr);
1335 hr = FolderItem_Verbs(item, &verbs);
1336 ok(hr == S_OK, "got 0x%08lx\n", hr);
1338 hr = FolderItem_Verbs(item, &verbs2);
1339 ok(hr == S_OK, "got 0x%08lx\n", hr);
1340 ok(verbs2 != verbs, "Unexpected verbs pointer.\n");
1341 FolderItemVerbs_Release(verbs2);
1343 disp = (void *)0xdeadbeef;
1344 hr = FolderItemVerbs_get_Application(verbs, &disp);
1345 ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr);
1346 ok(disp == NULL, "Unexpected application pointer.\n");
1348 disp = (void *)0xdeadbeef;
1349 hr = FolderItemVerbs_get_Parent(verbs, &disp);
1350 ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr);
1351 ok(disp == NULL, "Unexpected parent pointer %p.\n", disp);
1353 if (0) { /* crashes on winxp/win2k3 */
1354 hr = FolderItemVerbs_get_Count(verbs, NULL);
1355 ok(hr == E_INVALIDARG, "got 0x%08lx\n", hr);
1357 count = 0;
1358 hr = FolderItemVerbs_get_Count(verbs, &count);
1359 ok(hr == S_OK, "got 0x%08lx\n", hr);
1360 ok(count > 0, "got count %ld\n", count);
1362 if (0) { /* crashes on winxp/win2k3 */
1363 V_VT(&v) = VT_I4;
1364 V_I4(&v) = 0;
1365 hr = FolderItemVerbs_Item(verbs, v, NULL);
1366 ok(hr == E_INVALIDARG, "got 0x%08lx\n", hr);
1368 /* there's always one item more, so you can access [0,count],
1369 instead of actual [0,count) */
1370 for (i = 0; i <= count; i++) {
1371 V_VT(&v) = VT_I4;
1372 V_I4(&v) = i;
1373 hr = FolderItemVerbs_Item(verbs, v, &verb);
1374 ok(hr == S_OK, "got 0x%08lx\n", hr);
1375 hr = FolderItemVerb_get_Name(verb, &str);
1376 ok(hr == S_OK, "got 0x%08lx\n", hr);
1377 ok(str != NULL, "%ld: name %s\n", i, wine_dbgstr_w(str));
1378 if (i == count)
1379 ok(str[0] == 0, "%ld: got terminating item %s\n", i, wine_dbgstr_w(str));
1381 disp = (void *)0xdeadbeef;
1382 hr = FolderItemVerb_get_Parent(verb, &disp);
1383 ok(hr == E_NOTIMPL, "got %#lx.\n", hr);
1384 ok(disp == NULL, "Unexpected parent pointer %p.\n", disp);
1386 disp = (void *)0xdeadbeef;
1387 hr = FolderItemVerb_get_Application(verb, &disp);
1388 ok(hr == E_NOTIMPL, "got %#lx.\n", hr);
1389 ok(disp == NULL, "Unexpected parent pointer %p.\n", disp);
1391 SysFreeString(str);
1392 FolderItemVerb_Release(verb);
1395 V_VT(&v) = VT_I4;
1396 V_I4(&v) = count+1;
1397 verb = NULL;
1398 hr = FolderItemVerbs_Item(verbs, v, &verb);
1399 ok(hr == S_OK, "got 0x%08lx\n", hr);
1400 ok(verb == NULL, "got %p\n", verb);
1402 FolderItemVerbs_Release(verbs);
1403 FolderItem_Release(item);
1404 IShellDispatch_Release(sd);
1407 static void test_ShellLinkObject(void)
1409 HRESULT hr;
1410 IShellDispatch *sd;
1411 WCHAR path[MAX_PATH],
1412 empty_path[MAX_PATH],
1413 link_path[MAX_PATH];
1414 VARIANT v;
1415 Folder2 *folder2;
1416 Folder *folder;
1417 FolderItem *item;
1418 IDispatch *dispatch;
1419 IShellLinkW *sl;
1420 IShellLinkDual2* sld;
1421 IPersistFile *pf;
1422 BOOL ret;
1423 BSTR str;
1424 HANDLE file;
1425 int hk;
1427 hr = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER,
1428 &IID_IShellDispatch, (void**)&sd);
1429 ok(hr == S_OK, "got 0x%08lx\n", hr);
1431 GetTempPathW(MAX_PATH, path);
1432 V_VT(&v) = VT_BSTR;
1433 V_BSTR(&v) = SysAllocString(path);
1434 hr = IShellDispatch_NameSpace(sd, v, &folder);
1435 ok(hr == S_OK, "got 0x%08lx\n", hr);
1436 VariantClear(&v);
1438 hr = Folder_QueryInterface(folder, &IID_Folder2, (void**)&folder2);
1439 ok(hr == S_OK, "got 0x%08lx\n", hr);
1440 Folder_Release(folder);
1442 hr = Folder2_get_Self(folder2, &item);
1443 ok(hr == S_OK, "got 0x%08lx\n", hr);
1445 dispatch = (IDispatch*)0xdeadbeef;
1446 hr = FolderItem_get_GetLink(item, &dispatch);
1447 ok(hr == E_NOTIMPL, "got 0x%08lx\n", hr);
1448 ok(dispatch == NULL, "got %p\n", dispatch);
1450 FolderItem_Release(item);
1452 PathCombineW(empty_path, path, L"winetest_empty_file.txt");
1453 file = CreateFileW(empty_path, 0, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1454 ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %08lx\n", GetLastError());
1455 CloseHandle(file);
1457 hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (LPVOID*)&sl);
1458 ok(hr == S_OK, "got 0x%08lx\n", hr);
1459 hr = IShellLinkW_SetPath(sl, empty_path);
1460 ok(hr == S_OK, "got 0x%08lx\n", hr);
1461 hr = IShellLinkW_GetPath(sl, empty_path, MAX_PATH, NULL, 0);
1462 ok(hr == S_OK, "got 0x%08lx\n", hr);
1463 hr = IShellLinkW_SetDescription(sl, L"description");
1464 ok(hr == S_OK, "got 0x%08lx\n", hr);
1465 hr = IShellLinkW_SetWorkingDirectory(sl, L"working directory");
1466 ok(hr == S_OK, "got 0x%08lx\n", hr);
1467 hr = IShellLinkW_SetArguments(sl, L"arguments");
1468 ok(hr == S_OK, "got 0x%08lx\n", hr);
1469 hr = IShellLinkW_SetHotkey(sl, 1234);
1470 ok(hr == S_OK, "got 0x%08lx\n", hr);
1471 hr = IShellLinkW_SetShowCmd(sl, 1);
1472 ok(hr == S_OK, "got 0x%08lx\n", hr);
1474 hr = IShellLinkW_QueryInterface(sl, &IID_IPersistFile, (LPVOID*)&pf);
1475 ok(hr == S_OK, "got 0x%08lx\n", hr);
1477 PathCombineW(link_path, path, L"winetest_filled.lnk");
1478 hr = IPersistFile_Save(pf, link_path, TRUE);
1479 ok(hr == S_OK, "got 0x%08lx\n", hr);
1481 IPersistFile_Release(pf);
1482 IShellLinkW_Release(sl);
1484 str = SysAllocString(L"winetest_filled.lnk");
1485 hr = Folder2_ParseName(folder2, str, &item);
1486 ok(hr == S_OK, "got 0x%08lx\n", hr);
1487 SysFreeString(str);
1489 dispatch = NULL;
1490 hr = FolderItem_get_GetLink(item, &dispatch);
1491 ok(hr == S_OK, "got 0x%08lx\n", hr);
1492 ok(dispatch != NULL, "got %p\n", dispatch);
1494 if (dispatch) {
1495 sld = (IShellLinkDual2*)dispatch;
1497 str = NULL;
1498 hr = IShellLinkDual2_get_Path(sld, &str);
1499 ok(hr == S_OK, "got 0x%08lx\n", hr);
1500 if (hr == S_OK) {
1501 ok(!wcscmp(str, empty_path), "got %s (wanted %s)\n",
1502 wine_dbgstr_w(str), wine_dbgstr_w(empty_path));
1503 SysFreeString(str);
1506 str = NULL;
1507 hr = IShellLinkDual2_get_Description(sld, &str);
1508 todo_wine ok(hr == S_OK, "got 0x%08lx\n", hr);
1509 if (hr == S_OK) {
1510 ok(!wcscmp(str, L"description"), "got %s\n", wine_dbgstr_w(str));
1511 SysFreeString(str);
1514 str = NULL;
1515 hr = IShellLinkDual2_get_WorkingDirectory(sld, &str);
1516 todo_wine ok(hr == S_OK, "got 0x%08lx\n", hr);
1517 if (hr == S_OK) {
1518 ok(!wcscmp(str, L"working directory"), "got %s\n", wine_dbgstr_w(str));
1519 SysFreeString(str);
1522 str = NULL;
1523 hr = IShellLinkDual2_get_Arguments(sld, &str);
1524 todo_wine ok(hr == S_OK, "got 0x%08lx\n", hr);
1525 if (hr == S_OK) {
1526 ok(!wcscmp(str, L"arguments"), "got %s\n", wine_dbgstr_w(str));
1527 SysFreeString(str);
1530 hk = 0;
1531 hr = IShellLinkDual2_get_Hotkey(sld, &hk);
1532 todo_wine ok(hr == S_OK, "got 0x%08lx\n", hr);
1533 todo_wine ok(hk == 1234, "got %i\n", hk);
1535 hk = 0;
1536 hr = IShellLinkDual2_get_ShowCommand(sld, &hk);
1537 todo_wine ok(hr == S_OK, "got 0x%08lx\n", hr);
1538 todo_wine ok(hk == 1, "got %i\n", hk);
1540 IShellLinkDual2_Release(sld);
1543 FolderItem_Release(item);
1545 ret = DeleteFileW(link_path);
1546 ok(ret, "DeleteFile failed: %08lx\n", GetLastError());
1547 ret = DeleteFileW(empty_path);
1548 ok(ret, "DeleteFile failed: %08lx\n", GetLastError());
1550 Folder2_Release(folder2);
1552 IShellDispatch_Release(sd);
1555 static void test_ShellExecute(void)
1557 HRESULT hr;
1558 IShellDispatch2 *sd;
1559 BSTR name;
1560 VARIANT args, dir, op, show;
1562 static const WCHAR regW[] = {'r','e','g',0};
1564 hr = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER,
1565 &IID_IShellDispatch2, (void**)&sd);
1566 if (hr != S_OK)
1568 win_skip("IShellDispatch2 not supported\n");
1569 return;
1572 VariantInit(&args);
1573 VariantInit(&dir);
1574 VariantInit(&op);
1575 VariantInit(&show);
1577 V_VT(&show) = VT_I4;
1578 V_I4(&show) = 0;
1580 name = SysAllocString(regW);
1582 hr = IShellDispatch2_ShellExecute(sd, name, args, dir, op, show);
1583 ok(hr == S_OK, "ShellExecute failed: %08lx\n", hr);
1585 /* test invalid value for show */
1586 V_VT(&show) = VT_BSTR;
1587 V_BSTR(&show) = name;
1589 hr = IShellDispatch2_ShellExecute(sd, name, args, dir, op, show);
1590 ok(hr == S_OK, "ShellExecute failed: %08lx\n", hr);
1592 SysFreeString(name);
1593 IShellDispatch2_Release(sd);
1596 START_TEST(shelldispatch)
1598 HRESULT r;
1600 r = CoInitialize(NULL);
1601 ok(SUCCEEDED(r), "CoInitialize failed: %08lx\n", r);
1602 if (FAILED(r))
1603 return;
1605 init_function_pointers();
1606 test_namespace();
1607 test_items();
1608 test_service();
1609 test_ShellFolderViewDual();
1610 test_ShellWindows();
1611 test_ParseName();
1612 test_Verbs();
1613 test_ShellLinkObject();
1614 test_ShellExecute();
1616 CoUninitialize();