mfplat: Read queue subscriber within the critical section.
[wine/zf.git] / dlls / shell32 / tests / shelldispatch.c
blob33ada2d80ccda224d110691286ec9fd406176a86
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/heap.h"
31 #include "wine/test.h"
33 #include "initguid.h"
35 #define EXPECT_HR(hr,hr_exp) \
36 ok(hr == hr_exp, "got 0x%08x, expected 0x%08x\n", hr, hr_exp)
38 #define EXPECT_REF(obj,ref) _expect_ref((IUnknown *)obj, ref, __LINE__)
39 static void _expect_ref(IUnknown *obj, ULONG ref, int line)
41 ULONG rc;
42 IUnknown_AddRef(obj);
43 rc = IUnknown_Release(obj);
44 ok_(__FILE__,line)(rc == ref, "Unexpected refcount %d, expected %d\n", rc, ref);
47 static const WCHAR winetestW[] = {'w','i','n','e','t','e','s','t',0};
49 static HRESULT (WINAPI *pSHGetNameFromIDList)(PCIDLIST_ABSOLUTE,SIGDN,PWSTR*);
51 /* Updated Windows 7 has a new IShellDispatch6 in its typelib */
52 DEFINE_GUID(IID_IWin7ShellDispatch6, 0x34936ba1, 0x67ad, 0x4c41, 0x99,0xb8, 0x8c,0x12,0xdf,0xf1,0xe9,0x74);
54 static BSTR a2bstr(const char *str)
56 BSTR ret;
57 int len;
59 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
60 ret = SysAllocStringLen(NULL, len);
61 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
63 return ret;
66 static void variant_set_string(VARIANT *v, const char *s)
68 V_VT(v) = VT_BSTR;
69 V_BSTR(v) = a2bstr(s);
72 static void init_function_pointers(void)
74 HMODULE hshell32;
76 hshell32 = GetModuleHandleA("shell32.dll");
77 pSHGetNameFromIDList = (void*)GetProcAddress(hshell32, "SHGetNameFromIDList");
80 static void test_namespace(void)
82 static const ShellSpecialFolderConstants special_folders[] =
84 ssfDESKTOP,
85 ssfPROGRAMS,
86 ssfCONTROLS,
87 ssfPRINTERS,
88 ssfPERSONAL,
89 ssfFAVORITES,
90 ssfSTARTUP,
91 ssfRECENT,
92 ssfSENDTO,
93 ssfBITBUCKET,
94 ssfSTARTMENU,
95 ssfDESKTOPDIRECTORY,
96 ssfDRIVES,
97 ssfNETWORK,
98 ssfNETHOOD,
99 ssfFONTS,
100 ssfTEMPLATES,
101 ssfCOMMONSTARTMENU,
102 ssfCOMMONPROGRAMS,
103 ssfCOMMONSTARTUP,
104 ssfCOMMONDESKTOPDIR,
105 ssfAPPDATA,
106 ssfPRINTHOOD,
107 ssfLOCALAPPDATA,
108 ssfALTSTARTUP,
109 ssfCOMMONALTSTARTUP,
110 ssfCOMMONFAVORITES,
111 ssfINTERNETCACHE,
112 ssfCOOKIES,
113 ssfHISTORY,
114 ssfCOMMONAPPDATA,
115 ssfWINDOWS,
116 ssfSYSTEM,
117 ssfPROGRAMFILES,
118 ssfMYPICTURES,
119 ssfPROFILE,
120 ssfSYSTEMx86,
121 ssfPROGRAMFILESx86,
124 static const WCHAR backslashW[] = {'\\',0};
125 static const WCHAR clsidW[] = {
126 ':',':','{','6','4','5','F','F','0','4','0','-','5','0','8','1','-',
127 '1','0','1','B','-','9','F','0','8','-',
128 '0','0','A','A','0','0','2','F','9','5','4','E','}',0};
130 static WCHAR tempW[MAX_PATH], curW[MAX_PATH];
131 WCHAR *long_pathW = NULL;
132 HRESULT r;
133 IShellDispatch *sd;
134 Folder *folder;
135 Folder2 *folder2;
136 FolderItem *item;
137 VARIANT var;
138 BSTR title, item_path;
139 IDispatch *disp;
140 int len, i;
142 r = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, &IID_IShellDispatch, (void **)&sd);
143 ok(SUCCEEDED(r), "Failed to create ShellDispatch object: %#x.\n", r);
145 disp = NULL;
146 r = IShellDispatch_get_Application(sd, &disp);
147 ok(r == S_OK, "Failed to get application pointer, hr %#x.\n", r);
148 ok(disp == (IDispatch *)sd, "Unexpected application pointer %p.\n", disp);
149 IDispatch_Release(disp);
151 disp = NULL;
152 r = IShellDispatch_get_Parent(sd, &disp);
153 ok(r == S_OK, "Failed to get Shell object parent, hr %#x.\n", r);
154 ok(disp == (IDispatch *)sd, "Unexpected parent pointer %p.\n", disp);
155 IDispatch_Release(disp);
157 VariantInit(&var);
158 folder = (void*)0xdeadbeef;
159 r = IShellDispatch_NameSpace(sd, var, &folder);
160 ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r);
161 ok(folder == NULL, "expected NULL, got %p\n", folder);
163 /* test valid folder ids */
164 for (i = 0; i < ARRAY_SIZE(special_folders); i++)
166 V_VT(&var) = VT_I4;
167 V_I4(&var) = special_folders[i];
168 folder = (void*)0xdeadbeef;
169 r = IShellDispatch_NameSpace(sd, var, &folder);
170 if (special_folders[i] == ssfALTSTARTUP || special_folders[i] == ssfCOMMONALTSTARTUP)
171 todo_wine
172 ok(r == S_OK || broken(r == S_FALSE) /* winxp */, "Failed to get folder for index %#x, got %08x\n", special_folders[i], r);
173 else
174 ok(r == S_OK, "Failed to get folder for index %#x, got %08x\n", special_folders[i], r);
175 if (folder)
176 Folder_Release(folder);
179 V_VT(&var) = VT_I4;
180 V_I4(&var) = -1;
181 folder = (void *)0xdeadbeef;
182 r = IShellDispatch_NameSpace(sd, var, &folder);
183 ok(r == S_FALSE, "Unexpected hr %#x.\n", r);
184 ok(folder == NULL, "Unexpected folder instance %p\n", folder);
186 V_VT(&var) = VT_I4;
187 V_I4(&var) = ssfPROGRAMFILES;
188 r = IShellDispatch_NameSpace(sd, var, &folder);
189 ok(r == S_OK, "IShellDispatch::NameSpace failed: %08x\n", r);
190 if (r == S_OK)
192 static WCHAR path[MAX_PATH];
194 r = SHGetFolderPathW(NULL, CSIDL_PROGRAM_FILES, NULL, SHGFP_TYPE_CURRENT, path);
195 ok(r == S_OK, "Failed to get folder path: %#x.\n", r);
197 r = Folder_get_Title(folder, &title);
198 ok(r == S_OK, "Folder::get_Title failed: %08x\n", r);
199 if (r == S_OK)
201 /* On Win2000-2003 title is equal to program files directory name in
202 HKLM\Software\Microsoft\Windows\CurrentVersion\ProgramFilesDir.
203 On newer Windows it seems constant and is not changed
204 if the program files directory name is changed */
205 if (pSHGetNameFromIDList)
207 LPITEMIDLIST pidl;
208 PWSTR name;
210 r = SHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidl);
211 ok(r == S_OK, "SHGetSpecialFolderLocation failed: %08x\n", r);
212 r = pSHGetNameFromIDList(pidl, SIGDN_NORMALDISPLAY, &name);
213 ok(r == S_OK, "SHGetNameFromIDList failed: %08x\n", r);
214 ok(!lstrcmpW(title, name), "expected %s, got %s\n", wine_dbgstr_w(name), wine_dbgstr_w(title));
215 CoTaskMemFree(name);
216 CoTaskMemFree(pidl);
218 else
220 WCHAR *p;
222 p = path + lstrlenW(path);
223 while (path < p && *(p - 1) != '\\')
224 p--;
225 ok(!lstrcmpiW(title, p), "expected %s, got %s\n",
226 wine_dbgstr_w(p), wine_dbgstr_w(title));
228 SysFreeString(title);
230 r = Folder_QueryInterface(folder, &IID_Folder2, (LPVOID*)&folder2);
231 ok(r == S_OK, "Folder::QueryInterface failed: %08x\n", r);
232 if (r == S_OK)
234 r = Folder2_get_Self(folder2, &item);
235 ok(r == S_OK, "Folder::get_Self failed: %08x\n", r);
236 if (r == S_OK)
238 r = FolderItem_get_Path(item, &item_path);
239 ok(r == S_OK, "FolderItem::get_Path failed: %08x\n", r);
240 ok(!lstrcmpiW(item_path, path), "expected %s, got %s\n", wine_dbgstr_w(path), wine_dbgstr_w(item_path));
241 SysFreeString(item_path);
242 FolderItem_Release(item);
244 Folder2_Release(folder2);
246 Folder_Release(folder);
249 V_VT(&var) = VT_I4;
250 V_I4(&var) = ssfBITBUCKET;
251 r = IShellDispatch_NameSpace(sd, var, &folder);
252 ok(r == S_OK, "IShellDispatch::NameSpace failed: %08x\n", r);
254 r = Folder_QueryInterface(folder, &IID_Folder2, (void **)&folder2);
255 ok(r == S_OK, "Failed to get Folder2 interface: %#x.\n", r);
256 r = Folder2_get_Self(folder2, &item);
257 ok(r == S_OK, "Folder::get_Self failed: %08x\n", r);
258 r = FolderItem_get_Path(item, &item_path);
259 ok(r == S_OK, "FolderItem::get_Path failed: %08x\n", r);
260 /* TODO: we return lowercase GUID here */
261 ok(!lstrcmpiW(item_path, clsidW), "expected %s, got %s\n", wine_dbgstr_w(clsidW), wine_dbgstr_w(item_path));
263 SysFreeString(item_path);
264 FolderItem_Release(item);
265 Folder2_Release(folder2);
266 Folder_Release(folder);
268 GetTempPathW(MAX_PATH, tempW);
269 GetCurrentDirectoryW(MAX_PATH, curW);
270 SetCurrentDirectoryW(tempW);
271 CreateDirectoryW(winetestW, NULL);
272 V_VT(&var) = VT_BSTR;
273 V_BSTR(&var) = SysAllocString(winetestW);
274 r = IShellDispatch_NameSpace(sd, var, &folder);
275 ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r);
276 SysFreeString(V_BSTR(&var));
278 GetFullPathNameW(winetestW, MAX_PATH, tempW, NULL);
280 len = GetLongPathNameW(tempW, NULL, 0);
281 long_pathW = heap_alloc(len * sizeof(WCHAR));
282 GetLongPathNameW(tempW, long_pathW, len);
284 V_VT(&var) = VT_BSTR;
285 V_BSTR(&var) = SysAllocString(tempW);
286 r = IShellDispatch_NameSpace(sd, var, &folder);
287 ok(r == S_OK, "IShellDispatch::NameSpace failed: %08x\n", r);
289 disp = (void *)0xdeadbeef;
290 r = Folder_get_Parent(folder, &disp);
291 ok(r == E_NOTIMPL, "Unexpected hr %#x.\n", r);
292 ok(disp == NULL, "Unexpected parent pointer %p.\n", disp);
294 r = Folder_get_Title(folder, &title);
295 ok(r == S_OK, "Failed to get folder title: %#x.\n", r);
296 ok(!lstrcmpW(title, winetestW), "Unexpected title: %s\n", wine_dbgstr_w(title));
297 SysFreeString(title);
299 r = Folder_QueryInterface(folder, &IID_Folder2, (void **)&folder2);
300 ok(r == S_OK, "Failed to get Folder2 interface: %#x.\n", r);
301 r = Folder2_get_Self(folder2, &item);
302 ok(r == S_OK, "Folder::get_Self failed: %08x\n", r);
303 r = FolderItem_get_Path(item, &item_path);
304 ok(r == S_OK, "Failed to get item path: %#x.\n", r);
305 ok(!lstrcmpW(item_path, long_pathW), "Unexpected path %s, got %s\n", wine_dbgstr_w(item_path), wine_dbgstr_w(long_pathW));
306 SysFreeString(item_path);
307 FolderItem_Release(item);
308 Folder2_Release(folder2);
310 Folder_Release(folder);
311 VariantClear(&var);
313 len = lstrlenW(tempW);
314 if (len < MAX_PATH - 1)
316 lstrcatW(tempW, backslashW);
317 V_VT(&var) = VT_BSTR;
318 V_BSTR(&var) = SysAllocString(tempW);
319 r = IShellDispatch_NameSpace(sd, var, &folder);
320 ok(r == S_OK, "IShellDispatch::NameSpace failed: %08x\n", r);
321 if (r == S_OK)
323 r = Folder_get_Title(folder, &title);
324 ok(r == S_OK, "Folder::get_Title failed: %08x\n", r);
325 if (r == S_OK)
327 ok(!lstrcmpW(title, winetestW), "bad title: %s\n",
328 wine_dbgstr_w(title));
329 SysFreeString(title);
331 r = Folder_QueryInterface(folder, &IID_Folder2, (LPVOID*)&folder2);
332 ok(r == S_OK, "Failed to get Folder2 interface: %#x.\n", r);
333 if (r == S_OK)
335 r = Folder2_get_Self(folder2, &item);
336 ok(r == S_OK, "Folder::get_Self failed: %08x\n", r);
337 if (r == S_OK)
339 r = FolderItem_get_Path(item, &item_path);
340 ok(r == S_OK, "FolderItem::get_Path failed: %08x\n", r);
341 ok(!lstrcmpW(item_path, long_pathW), "Unexpected path %s, got %s\n", wine_dbgstr_w(item_path),
342 wine_dbgstr_w(long_pathW));
343 SysFreeString(item_path);
344 FolderItem_Release(item);
346 Folder2_Release(folder2);
348 Folder_Release(folder);
350 SysFreeString(V_BSTR(&var));
353 heap_free(long_pathW);
354 RemoveDirectoryW(winetestW);
355 SetCurrentDirectoryW(curW);
356 IShellDispatch_Release(sd);
359 static void test_items(void)
361 static const struct
363 char name[32];
364 enum
366 DIRECTORY,
367 EMPTY_FILE,
369 type;
371 file_defs[] =
373 { "00-Myfolder", DIRECTORY },
374 { "01-empty.bin", EMPTY_FILE },
376 WCHAR path[MAX_PATH], cur_dir[MAX_PATH], orig_dir[MAX_PATH];
377 HRESULT r;
378 IShellDispatch *sd = NULL;
379 Folder *folder = NULL;
380 FolderItems *items;
381 FolderItems2 *items2 = NULL;
382 FolderItems3 *items3 = NULL;
383 FolderItem *item = (FolderItem*)0xdeadbeef, *item2;
384 FolderItemVerbs *verbs = (FolderItemVerbs*)0xdeadbeef;
385 VARIANT var, var2, int_index, str_index, str_index2;
386 IDispatch *disp, *disp2;
387 LONG count = -1;
388 IUnknown *unk;
389 HANDLE file;
390 BSTR bstr;
391 char cstr[64];
392 BOOL ret;
393 int i;
395 r = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, &IID_IShellDispatch, (void**)&sd);
396 ok(SUCCEEDED(r), "CoCreateInstance failed: %08x\n", r);
397 ok(!!sd, "sd is null\n");
399 /* create and enter a temporary directory and a folder object for it */
400 GetTempPathW(MAX_PATH, path);
401 GetCurrentDirectoryW(MAX_PATH, orig_dir);
402 SetCurrentDirectoryW(path);
403 ret = CreateDirectoryW(winetestW, NULL);
404 ok(ret, "CreateDirectory failed: %08x\n", GetLastError());
405 GetFullPathNameW(winetestW, MAX_PATH, path, NULL);
406 V_VT(&var) = VT_BSTR;
407 V_BSTR(&var) = SysAllocString(path);
409 EXPECT_REF(sd, 1);
410 r = IShellDispatch_NameSpace(sd, var, &folder);
411 ok(r == S_OK, "IShellDispatch::NameSpace failed: %08x\n", r);
412 ok(!!folder, "folder is null\n");
413 EXPECT_REF(folder, 1);
414 EXPECT_REF(sd, 1);
416 VariantClear(&var);
417 SetCurrentDirectoryW(winetestW);
418 GetCurrentDirectoryW(MAX_PATH, path);
419 GetLongPathNameW(path, cur_dir, MAX_PATH);
421 /* FolderItems grabs its Folder reference */
422 items = NULL;
423 r = Folder_Items(folder, &items);
424 ok(r == S_OK, "Folder::Items failed: %08x\n", r);
425 ok(!!items, "items is null\n");
426 EXPECT_REF(folder, 2);
427 EXPECT_REF(items, 1);
429 unk = NULL;
430 r = Folder_Items(folder, (FolderItems **)&unk);
431 ok(r == S_OK, "Folder::Items failed: %08x\n", r);
432 EXPECT_REF(folder, 3);
433 IUnknown_Release(unk);
434 EXPECT_REF(folder, 2);
436 FolderItems_AddRef(items);
437 EXPECT_REF(folder, 2);
438 FolderItems_Release(items);
440 /* Application property */
441 disp = NULL;
442 EXPECT_REF(sd, 1);
443 r = Folder_get_Application(folder, &disp);
444 ok(r == S_OK, "Failed to get application %#x.\n", r);
445 ok(disp != (IDispatch *)sd, "Unexpected application pointer\n");
446 EXPECT_REF(sd, 1);
448 disp2 = NULL;
449 r = Folder_get_Application(folder, &disp2);
450 ok(r == S_OK, "Failed to get application %#x.\n", r);
451 ok(disp2 == disp, "Unexpected application pointer\n");
452 IDispatch_Release(disp2);
454 r = IDispatch_QueryInterface(disp, &IID_IShellDispatch, (void **)&disp2);
455 ok(r == S_OK, "Wrong instance, hr %#x.\n", r);
456 IDispatch_Release(disp2);
457 IDispatch_Release(disp);
459 if (0) /* crashes on all versions of Windows */
460 r = FolderItems_get_Count(items, NULL);
462 r = FolderItems_get_Count(items, &count);
463 ok(r == S_OK, "FolderItems::get_Count failed: %08x\n", r);
464 ok(!count, "expected 0 files, got %d\n", count);
466 V_VT(&var) = VT_I4;
467 V_I4(&var) = 0;
469 if (0) /* crashes on all versions of Windows */
470 r = FolderItems_Item(items, var, NULL);
472 r = FolderItems_Item(items, var, &item);
473 ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r);
474 ok(!item, "item is not null\n");
476 /* create test files */
477 for (i = 0; i < ARRAY_SIZE(file_defs); i++)
479 switch (file_defs[i].type)
481 case DIRECTORY:
482 r = CreateDirectoryA(file_defs[i].name, NULL);
483 ok(r, "CreateDirectory failed: %08x\n", GetLastError());
484 PathCombineA(cstr, file_defs[i].name, "foo.txt");
485 file = CreateFileA(cstr, 0, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
486 ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %08x\n", GetLastError());
487 CloseHandle(file);
488 break;
490 case EMPTY_FILE:
491 file = CreateFileA(file_defs[i].name, 0, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
492 ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %08x\n", GetLastError());
493 CloseHandle(file);
494 break;
498 /* test that get_Count is not aware of the newly created files */
499 count = -1;
500 r = FolderItems_get_Count(items, &count);
501 ok(r == S_OK, "FolderItems::get_Count failed: %08x\n", r);
502 ok(!count, "expected 0 files, got %d\n", count);
504 /* test that the newly created files CAN be retrieved by string index */
505 variant_set_string(&var, file_defs[0].name);
506 item = NULL;
507 r = FolderItems_Item(items, var, &item);
508 ok(r == S_OK, "FolderItems::Item failed: %08x\n", r);
509 ok(!!item, "item is null\n");
511 disp = (void *)0xdeadbeef;
512 r = FolderItems_get_Parent(items, &disp);
513 ok(r == E_NOTIMPL, "Unexpected hr %#x.\n", r);
514 ok(disp == NULL, "Unexpected parent pointer %p.\n", disp);
516 r = FolderItem_get_Parent(item, &disp);
517 ok(r == S_OK, "Failed to get parent pointer, hr %#x.\n", r);
518 ok(disp == (IDispatch *)folder, "Unexpected parent pointer %p.\n", disp);
519 IDispatch_Release(disp);
521 if (item) FolderItem_Release(item);
522 VariantClear(&var);
524 /* recreate the items object */
525 FolderItems_Release(items);
526 items = NULL;
527 r = Folder_Items(folder, &items);
528 ok(r == S_OK, "Folder::Items failed: %08x\n", r);
529 ok(!!items, "items is null\n");
530 r = FolderItems_QueryInterface(items, &IID_FolderItems2, (void**)&items2);
531 ok(r == S_OK || broken(r == E_NOINTERFACE) /* xp and later */, "FolderItems::QueryInterface failed: %08x\n", r);
532 if (r == S_OK)
534 ok(!!items2, "items2 is null\n");
535 FolderItems2_Release(items2);
537 r = FolderItems_QueryInterface(items, &IID_FolderItems3, (void**)&items3);
538 ok(r == S_OK, "FolderItems::QueryInterface failed: %08x\n", r);
539 ok(!!items3, "items3 is null\n");
541 count = -1;
542 r = FolderItems_get_Count(items, &count);
543 ok(r == S_OK, "FolderItems::get_Count failed: %08x\n", r);
544 ok(count == ARRAY_SIZE(file_defs), "got %d files\n", count);
546 /* VT_EMPTY */
547 V_VT(&var) = VT_EMPTY;
548 item = (FolderItem*)0xdeadbeef;
549 r = FolderItems_Item(items, var, &item);
550 ok(r == E_NOTIMPL, "expected E_NOTIMPL, got %08x\n", r);
551 ok(!item, "item is not null\n");
553 /* VT_I2 */
554 V_VT(&var) = VT_I2;
555 V_I2(&var) = 0;
557 EXPECT_REF(folder, 2);
558 EXPECT_REF(items, 2);
559 item = NULL;
560 r = FolderItems_Item(items, var, &item);
561 ok(r == S_OK, "FolderItems::Item failed: %08x\n", r);
562 ok(!!item, "item is null\n");
563 EXPECT_REF(folder, 3);
564 EXPECT_REF(items, 2);
566 r = Folder_get_Application(folder, &disp);
567 ok(r == S_OK, "Failed to get application pointer %#x.\n", r);
568 r = FolderItem_get_Application(item, &disp2);
569 ok(r == S_OK, "Failed to get application pointer %#x.\n", r);
570 ok(disp == disp2, "Unexpected application pointer.\n");
571 IDispatch_Release(disp2);
572 IDispatch_Release(disp);
574 FolderItem_Release(item);
576 /* VT_VARIANT | VT_BYREF */
577 V_VT(&var2) = VT_I2;
578 V_I2(&var2) = 0;
580 V_VT(&var) = VT_BYREF | VT_VARIANT;
581 V_VARIANTREF(&var) = &var2;
583 item = NULL;
584 r = FolderItems_Item(items, var, &item);
585 ok(r == S_OK, "FolderItems::Item failed: %08x\n", r);
586 ok(!!item, "item is null\n");
587 FolderItem_Release(item);
589 /* VT_I4 */
590 V_VT(&var) = VT_I4;
591 V_I4(&var) = 0;
592 item = NULL;
593 r = FolderItems_Item(items, var, &item);
594 ok(r == S_OK, "FolderItems::Item failed: %08x\n", r);
595 ok(!!item, "item is null\n");
596 if (item) FolderItem_Release(item);
598 V_I4(&var) = -1;
599 item = (FolderItem*)0xdeadbeef;
600 r = FolderItems_Item(items, var, &item);
601 ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r);
602 ok(!item, "item is not null\n");
604 V_VT(&var) = VT_ERROR;
605 V_ERROR(&var) = 0;
606 item = NULL;
607 r = FolderItems_Item(items, var, &item);
608 ok(r == S_OK, "expected S_OK, got %08x\n", r);
609 ok(!!item, "item is null\n");
610 if (item)
612 bstr = NULL;
613 r = FolderItem_get_Path(item, &bstr);
614 ok(r == S_OK, "FolderItem::get_Path failed: %08x\n", r);
615 ok(!lstrcmpW(bstr, cur_dir),
616 "expected %s, got %s\n", wine_dbgstr_w(cur_dir), wine_dbgstr_w(bstr));
617 SysFreeString(bstr);
618 FolderItem_Release(item);
621 V_VT(&int_index) = VT_I4;
623 /* test the folder item corresponding to each file */
624 for (i = 0; i < ARRAY_SIZE(file_defs); i++)
626 VARIANT_BOOL b;
627 BSTR name;
629 V_I4(&int_index) = i;
630 variant_set_string(&str_index, file_defs[i].name);
632 item = NULL;
633 r = FolderItems_Item(items, int_index, &item);
634 ok(r == S_OK, "file_defs[%d]: FolderItems::Item failed: %08x\n", i, r);
635 ok(!!item, "file_defs[%d]: item is null\n", i);
637 item2 = NULL;
638 r = FolderItems_Item(items, int_index, &item2);
639 ok(r == S_OK, "file_defs[%d]: FolderItems::Item failed: %08x\n", i, r);
640 ok(item2 != item, "file_defs[%d]: item and item2 are the same\n", i);
641 FolderItem_Release(item2);
643 bstr = NULL;
644 r = FolderItem_get_Path(item, &bstr);
645 ok(r == S_OK, "file_defs[%d]: FolderItem::get_Path failed: %08x\n", i, r);
646 PathCombineW(path, cur_dir, V_BSTR(&str_index));
647 ok(!lstrcmpW(bstr, path),
648 "file_defs[%d]: expected %s, got %s\n", i, wine_dbgstr_w(path), wine_dbgstr_w(bstr));
649 SysFreeString(bstr);
651 bstr = a2bstr(file_defs[i].name);
652 r = FolderItem_get_Name(item, &name);
653 ok(r == S_OK, "Failed to get item name, hr %#x.\n", r);
654 /* Returned display name does not have to strictly match file name, e.g. extension could be omitted. */
655 ok(lstrlenW(name) <= lstrlenW(bstr), "file_defs[%d]: unexpected name length.\n", i);
656 ok(!memcmp(bstr, name, lstrlenW(name) * sizeof(WCHAR)), "file_defs[%d]: unexpected name %s.\n", i, wine_dbgstr_w(name));
657 SysFreeString(name);
658 SysFreeString(bstr);
660 FolderItem_Release(item);
662 item = NULL;
663 r = FolderItems_Item(items, str_index, &item);
664 ok(r == S_OK, "file_defs[%d]: FolderItems::Item failed: %08x\n", i, r);
665 ok(!!item, "file_defs[%d]: item is null\n", i);
667 bstr = NULL;
668 r = FolderItem_get_Path(item, &bstr);
669 ok(r == S_OK, "file_defs[%d]: FolderItem::get_Path failed: %08x\n", i, r);
670 PathCombineW(path, cur_dir, V_BSTR(&str_index));
671 ok(!lstrcmpW(bstr, path),
672 "file_defs[%d]: expected %s, got %s\n", i, wine_dbgstr_w(path), wine_dbgstr_w(bstr));
673 SysFreeString(bstr);
675 b = 0xdead;
676 r = FolderItem_get_IsFolder(item, &b);
677 ok(r == S_OK, "Failed to get IsFolder property, %#x.\n", r);
678 ok(file_defs[i].type == DIRECTORY ? b == VARIANT_TRUE : b == VARIANT_FALSE, "Unexpected prop value %#x.\n", b);
680 FolderItem_Release(item);
682 if (file_defs[i].type == DIRECTORY)
684 /* test that getting an item object for a file in a subdirectory succeeds */
685 PathCombineA(cstr, file_defs[i].name, "foo.txt");
686 variant_set_string(&str_index2, cstr);
687 item2 = NULL;
688 r = FolderItems_Item(items, str_index2, &item2);
689 ok(r == S_OK, "file_defs[%d]: FolderItems::Item failed: %08x\n", i, r);
690 ok(!!item2, "file_defs[%d]: item is null\n", i);
691 if (item2) FolderItem_Release(item2);
692 VariantClear(&str_index2);
694 /* delete the file in the subdirectory */
695 ret = DeleteFileA(cstr);
696 ok(ret, "file_defs[%d]: DeleteFile failed: %08x\n", i, GetLastError());
698 /* test that getting an item object via a relative path fails */
699 strcpy(cstr, file_defs[i].name);
700 strcat(cstr, "\\..\\");
701 strcat(cstr, file_defs[i].name);
702 variant_set_string(&str_index2, cstr);
703 item2 = (FolderItem*)0xdeadbeef;
704 r = FolderItems_Item(items, str_index2, &item2);
705 todo_wine {
706 ok(r == S_FALSE, "file_defs[%d]: expected S_FALSE, got %08x\n", i, r);
707 ok(!item2, "file_defs[%d]: item is not null\n", i);
709 if (item2) FolderItem_Release(item2);
710 VariantClear(&str_index2);
712 /* remove the directory */
713 ret = RemoveDirectoryA(file_defs[i].name);
714 ok(ret, "file_defs[%d]: RemoveDirectory failed: %08x\n", i, GetLastError());
716 else
718 ret = DeleteFileA(file_defs[i].name);
719 ok(ret, "file_defs[%d]: DeleteFile failed: %08x\n", i, GetLastError());
722 /* test that the folder item is still accessible by integer index */
723 item = NULL;
724 r = FolderItems_Item(items, int_index, &item);
725 ok(r == S_OK, "file_defs[%d]: FolderItems::Item failed: %08x\n", i, r);
726 ok(!!item, "file_defs[%d]: item is null\n", i);
728 bstr = NULL;
729 r = FolderItem_get_Path(item, &bstr);
730 ok(r == S_OK, "file_defs[%d]: FolderItem::get_Path failed: %08x\n", i, r);
731 PathCombineW(path, cur_dir, V_BSTR(&str_index));
732 ok(!lstrcmpW(bstr, path),
733 "file_defs[%d]: expected %s, got %s\n", i, wine_dbgstr_w(path), wine_dbgstr_w(bstr));
734 SysFreeString(bstr);
736 FolderItem_Release(item);
738 /* test that the folder item is no longer accessible by string index */
739 item = (FolderItem*)0xdeadbeef;
740 r = FolderItems_Item(items, str_index, &item);
741 ok(r == S_FALSE, "file_defs[%d]: expected S_FALSE, got %08x\n", i, r);
742 ok(!item, "file_defs[%d]: item is not null\n", i);
744 VariantClear(&str_index);
747 /* test that there are only as many folder items as there were files */
748 V_I4(&int_index) = ARRAY_SIZE(file_defs);
749 item = (FolderItem*)0xdeadbeef;
750 r = FolderItems_Item(items, int_index, &item);
751 ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r);
752 ok(!item, "item is not null\n");
754 if (0) /* crashes on xp */
756 r = FolderItems_get_Application(items, NULL);
757 ok(r == E_INVALIDARG, "expected E_INVALIDARG, got %08x\n", r);
760 r = FolderItems_get_Application(items, &disp);
761 ok(r == S_OK, "FolderItems::get_Application failed: %08x\n", r);
763 r = Folder_get_Application(folder, &disp2);
764 ok(r == S_OK, "Failed to get application pointer, hr %#x.\n", r);
765 ok(disp == disp2, "Unexpected application pointer.\n");
766 IDispatch_Release(disp2);
767 IDispatch_Release(disp);
769 if (0) /* crashes on xp */
771 r = FolderItems_get_Parent(items, NULL);
772 ok(r == E_NOTIMPL, "expected E_NOTIMPL, got %08x\n", r);
775 disp = (IDispatch*)0xdeadbeef;
776 r = FolderItems_get_Parent(items, &disp);
777 ok(r == E_NOTIMPL, "expected E_NOTIMPL, got %08x\n", r);
778 ok(!disp, "disp is not null\n");
780 if (0) /* crashes on xp */
782 r = FolderItems__NewEnum(items, NULL);
783 ok(r == E_INVALIDARG, "expected E_INVALIDARG, got %08x\n", r);
786 r = FolderItems__NewEnum(items, &unk);
787 todo_wine
788 ok(r == S_OK, "FolderItems::_NewEnum failed: %08x\n", r);
789 todo_wine
790 ok(!!unk, "unk is null\n");
791 if (unk) IUnknown_Release(unk);
793 if (items3)
795 r = FolderItems3_Filter(items3, 0, NULL);
796 todo_wine
797 ok(r == S_OK, "expected S_OK, got %08x\n", r);
799 if (0) /* crashes on xp */
801 r = FolderItems3_get_Verbs(items3, NULL);
802 ok(r == E_INVALIDARG, "expected E_INVALIDARG, got %08x\n", r);
805 r = FolderItems3_get_Verbs(items3, &verbs);
806 todo_wine
807 ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r);
808 ok(!verbs, "verbs is not null\n");
811 /* remove the temporary directory and restore the original working directory */
812 GetTempPathW(MAX_PATH, path);
813 SetCurrentDirectoryW(path);
814 ret = RemoveDirectoryW(winetestW);
815 ok(ret, "RemoveDirectory failed: %08x\n", GetLastError());
816 SetCurrentDirectoryW(orig_dir);
818 /* test that everything stops working after the directory has been removed */
819 count = -1;
820 r = FolderItems_get_Count(items, &count);
821 ok(r == S_OK, "FolderItems::get_Count failed: %08x\n", r);
822 ok(!count, "expected 0 files, got %d\n", count);
824 item = NULL;
825 V_I4(&int_index) = 0;
826 item = (FolderItem*)0xdeadbeef;
827 r = FolderItems_Item(items, int_index, &item);
828 ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r);
829 ok(!item, "item is not null\n");
831 variant_set_string(&str_index, file_defs[0].name);
832 item = (FolderItem*)0xdeadbeef;
833 r = FolderItems_Item(items, str_index, &item);
834 ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r);
835 ok(!item, "item is not null\n");
836 VariantClear(&str_index);
838 FolderItems_Release(items);
839 Folder_Release(folder);
840 if (items3) FolderItems3_Release(items3);
841 IShellDispatch_Release(sd);
844 static void test_service(void)
846 static const WCHAR spooler[] = {'S','p','o','o','l','e','r',0};
847 static const WCHAR dummyW[] = {'d','u','m','m','y',0};
848 SERVICE_STATUS_PROCESS status;
849 SC_HANDLE scm, service;
850 IShellDispatch2 *sd;
851 DWORD dummy;
852 HRESULT hr;
853 BSTR name;
854 VARIANT v;
856 hr = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER,
857 &IID_IShellDispatch2, (void**)&sd);
858 if (hr != S_OK)
860 win_skip("IShellDispatch2 not supported\n");
861 return;
864 V_VT(&v) = VT_I2;
865 V_I2(&v) = 10;
866 hr = IShellDispatch2_IsServiceRunning(sd, NULL, &v);
867 ok(V_VT(&v) == VT_BOOL, "got %d\n", V_VT(&v));
868 ok(V_BOOL(&v) == VARIANT_FALSE, "got %d\n", V_BOOL(&v));
869 EXPECT_HR(hr, S_OK);
871 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
872 service = OpenServiceW(scm, spooler, SERVICE_QUERY_STATUS);
873 QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy);
874 CloseServiceHandle(service);
875 CloseServiceHandle(scm);
877 /* service should exist */
878 name = SysAllocString(spooler);
879 V_VT(&v) = VT_I2;
880 hr = IShellDispatch2_IsServiceRunning(sd, name, &v);
881 EXPECT_HR(hr, S_OK);
882 ok(V_VT(&v) == VT_BOOL, "got %d\n", V_VT(&v));
883 if (status.dwCurrentState == SERVICE_RUNNING)
884 ok(V_BOOL(&v) == VARIANT_TRUE, "got %d\n", V_BOOL(&v));
885 else
886 ok(V_BOOL(&v) == VARIANT_FALSE, "got %d\n", V_BOOL(&v));
887 SysFreeString(name);
889 /* service doesn't exist */
890 name = SysAllocString(dummyW);
891 V_VT(&v) = VT_I2;
892 hr = IShellDispatch2_IsServiceRunning(sd, name, &v);
893 EXPECT_HR(hr, S_OK);
894 ok(V_VT(&v) == VT_BOOL, "got %d\n", V_VT(&v));
895 ok(V_BOOL(&v) == VARIANT_FALSE, "got %d\n", V_BOOL(&v));
896 SysFreeString(name);
898 IShellDispatch2_Release(sd);
901 static void test_dispatch_typeinfo(IDispatch *disp, REFIID *riid)
903 ITypeInfo *typeinfo;
904 TYPEATTR *typeattr;
905 UINT count;
906 HRESULT hr;
908 count = 10;
909 hr = IDispatch_GetTypeInfoCount(disp, &count);
910 ok(hr == S_OK, "got 0x%08x\n", hr);
911 ok(count == 1, "got %u\n", count);
913 hr = IDispatch_GetTypeInfo(disp, 0, LOCALE_SYSTEM_DEFAULT, &typeinfo);
914 ok(hr == S_OK, "got 0x%08x\n", hr);
916 hr = ITypeInfo_GetTypeAttr(typeinfo, &typeattr);
917 ok(hr == S_OK, "got 0x%08x\n", hr);
918 while (!IsEqualGUID(*riid, &IID_NULL)) {
919 if (IsEqualGUID(&typeattr->guid, *riid))
920 break;
921 riid++;
923 ok(IsEqualGUID(&typeattr->guid, *riid), "unexpected type guid %s\n", wine_dbgstr_guid(&typeattr->guid));
925 ITypeInfo_ReleaseTypeAttr(typeinfo, typeattr);
926 ITypeInfo_Release(typeinfo);
929 static void test_ShellFolderViewDual(void)
931 static const IID *shelldisp_riids[] = {
932 &IID_IShellDispatch6,
933 &IID_IShellDispatch5,
934 &IID_IShellDispatch4,
935 &IID_IShellDispatch2,
936 &IID_IWin7ShellDispatch6,
937 &IID_NULL
939 IShellFolderViewDual *viewdual;
940 IShellFolder *desktop, *tmpdir;
941 IShellView *view, *view2;
942 IDispatch *disp, *disp2;
943 WCHAR pathW[MAX_PATH];
944 LPITEMIDLIST pidl;
945 HRESULT hr;
947 /* IShellFolderViewDual is not an IShellView extension */
948 hr = SHGetDesktopFolder(&desktop);
949 ok(hr == S_OK, "got 0x%08x\n", hr);
951 hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
952 ok(hr == S_OK, "got 0x%08x\n", hr);
954 hr = IShellView_QueryInterface(view, &IID_IShellFolderViewDual, (void**)&viewdual);
955 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
957 hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IDispatch, (void**)&disp);
958 ok(hr == S_OK, "got 0x%08x\n", hr);
960 hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IDispatch, (void**)&disp2);
961 ok(hr == S_OK, "got 0x%08x\n", hr);
962 ok(disp2 == disp, "got %p, %p\n", disp2, disp);
963 IDispatch_Release(disp2);
965 hr = IDispatch_QueryInterface(disp, &IID_IShellFolderViewDual, (void**)&viewdual);
966 ok(hr == S_OK, "got 0x%08x\n", hr);
967 ok(disp == (IDispatch*)viewdual, "got %p, expected %p\n", viewdual, disp);
969 hr = IShellFolderViewDual_QueryInterface(viewdual, &IID_IShellView, (void**)&view2);
970 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
972 /* get_Application() */
974 if (0) /* crashes on pre-vista */ {
975 hr = IShellFolderViewDual_get_Application(viewdual, NULL);
976 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
978 hr = IShellFolderViewDual_get_Application(viewdual, &disp2);
979 ok(hr == S_OK, "got 0x%08x\n", hr);
980 ok(disp2 != (IDispatch*)viewdual, "got %p, %p\n", disp2, viewdual);
981 test_dispatch_typeinfo(disp2, shelldisp_riids);
982 IDispatch_Release(disp2);
984 IShellFolderViewDual_Release(viewdual);
985 IDispatch_Release(disp);
987 disp = (void*)0xdeadbeef;
988 hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IShellFolderViewDual, (void**)&disp);
989 ok(hr == E_NOINTERFACE || broken(hr == E_NOTIMPL) /* win2k */, "got 0x%08x\n", hr);
990 ok(disp == NULL, "got %p\n", disp);
991 IShellView_Release(view);
993 /* Try with some other folder, that's not a desktop */
994 GetTempPathW(ARRAY_SIZE(pathW), pathW);
995 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, pathW, NULL, &pidl, NULL);
996 ok(hr == S_OK, "got 0x%08x\n", hr);
998 hr = IShellFolder_BindToObject(desktop, pidl, NULL, &IID_IShellFolder, (void**)&tmpdir);
999 ok(hr == S_OK, "got 0x%08x\n", hr);
1000 CoTaskMemFree(pidl);
1002 hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
1003 ok(hr == S_OK, "got 0x%08x\n", hr);
1005 hr = IShellView_QueryInterface(view, &IID_IShellFolderViewDual, (void**)&viewdual);
1006 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
1008 hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IDispatch, (void**)&disp);
1009 ok(hr == S_OK, "got 0x%08x\n", hr);
1010 IDispatch_Release(disp);
1011 IShellView_Release(view);
1013 IShellFolder_Release(tmpdir);
1014 IShellFolder_Release(desktop);
1017 static void test_ShellWindows(void)
1019 IShellWindows *shellwindows;
1020 LONG cookie, cookie2, ret;
1021 ITEMIDLIST *pidl;
1022 IDispatch *disp;
1023 VARIANT v, v2;
1024 HRESULT hr;
1025 HWND hwnd;
1027 hr = CoCreateInstance(&CLSID_ShellWindows, NULL, CLSCTX_LOCAL_SERVER,
1028 &IID_IShellWindows, (void**)&shellwindows);
1029 ok(hr == S_OK, "got 0x%08x\n", hr);
1030 /* TODO: remove when explorer startup with clean prefix is fixed */
1031 if (hr != S_OK)
1032 return;
1034 hr = IShellWindows_Register(shellwindows, NULL, 0, SWC_EXPLORER, NULL);
1035 ok(hr == HRESULT_FROM_WIN32(RPC_X_NULL_REF_POINTER), "got 0x%08x\n", hr);
1037 hr = IShellWindows_Register(shellwindows, NULL, 0, SWC_EXPLORER, &cookie);
1038 ok(hr == E_POINTER, "got 0x%08x\n", hr);
1040 hr = IShellWindows_Register(shellwindows, (IDispatch*)shellwindows, 0, SWC_EXPLORER, &cookie);
1041 ok(hr == E_POINTER, "got 0x%08x\n", hr);
1043 hr = IShellWindows_Register(shellwindows, (IDispatch*)shellwindows, 0, SWC_EXPLORER, &cookie);
1044 ok(hr == E_POINTER, "got 0x%08x\n", hr);
1046 hwnd = CreateWindowExA(0, "button", "test", BS_CHECKBOX | WS_VISIBLE | WS_POPUP,
1047 0, 0, 50, 14, 0, 0, 0, NULL);
1048 ok(hwnd != NULL, "got %p, error %d\n", hwnd, GetLastError());
1050 cookie = 0;
1051 hr = IShellWindows_Register(shellwindows, NULL, HandleToLong(hwnd), SWC_EXPLORER, &cookie);
1052 ok(hr == S_OK, "got 0x%08x\n", hr);
1053 ok(cookie != 0, "got %d\n", cookie);
1055 cookie2 = 0;
1056 hr = IShellWindows_Register(shellwindows, NULL, HandleToLong(hwnd), SWC_EXPLORER, &cookie2);
1057 ok(hr == S_OK, "got 0x%08x\n", hr);
1058 ok(cookie2 != 0 && cookie2 != cookie, "got %d\n", cookie2);
1060 pidl = ILCreateFromPathA("C:\\");
1061 V_VT(&v) = VT_ARRAY | VT_UI1;
1062 V_ARRAY(&v) = SafeArrayCreateVector(VT_UI1, 0, ILGetSize(pidl));
1063 memcpy(V_ARRAY(&v)->pvData, pidl, ILGetSize(pidl));
1065 VariantInit(&v2);
1066 hr = IShellWindows_FindWindowSW(shellwindows, &v, &v2, SWC_EXPLORER, &ret, 0, &disp);
1067 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1068 ok(!ret, "Got window %#x.\n", ret);
1069 ok(!disp, "Got IDispatch %p.\n", &disp);
1071 hr = IShellWindows_OnNavigate(shellwindows, 0, &v);
1072 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
1074 hr = IShellWindows_OnNavigate(shellwindows, cookie, &v);
1075 ok(hr == S_OK, "Got hr %#x.\n", hr);
1077 hr = IShellWindows_FindWindowSW(shellwindows, &v, &v2, SWC_EXPLORER, &ret, 0, &disp);
1078 ok(hr == S_OK, "Got hr %#x.\n", hr);
1079 ok(ret == (LONG)(LONG_PTR)hwnd, "Expected %p, got %#x.\n", hwnd, ret);
1080 ok(!disp, "Got IDispatch %p.\n", &disp);
1082 hr = IShellWindows_Revoke(shellwindows, cookie);
1083 ok(hr == S_OK, "got 0x%08x\n", hr);
1085 hr = IShellWindows_FindWindowSW(shellwindows, &v, &v2, SWC_EXPLORER, &ret, 0, &disp);
1086 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1087 ok(!ret, "Got window %#x.\n", ret);
1088 ok(!disp, "Got IDispatch %p.\n", &disp);
1090 hr = IShellWindows_Revoke(shellwindows, cookie2);
1091 ok(hr == S_OK, "got 0x%08x\n", hr);
1093 hr = IShellWindows_Revoke(shellwindows, 0);
1094 ok(hr == S_FALSE, "got 0x%08x\n", hr);
1096 /* we can register ourselves as desktop, but FindWindowSW still returns real desktop window */
1097 cookie = 0;
1098 hr = IShellWindows_Register(shellwindows, NULL, HandleToLong(hwnd), SWC_DESKTOP, &cookie);
1099 ok(hr == S_OK, "got 0x%08x\n", hr);
1100 ok(cookie != 0, "got %d\n", cookie);
1102 disp = (void*)0xdeadbeef;
1103 ret = 0xdead;
1104 VariantInit(&v);
1105 hr = IShellWindows_FindWindowSW(shellwindows, &v, &v, SWC_DESKTOP, &ret, SWFO_NEEDDISPATCH, &disp);
1106 ok(hr == S_OK || broken(hr == S_FALSE), "got 0x%08x\n", hr);
1107 if (hr == S_FALSE) /* winxp and earlier */ {
1108 win_skip("SWC_DESKTOP is not supported, some tests will be skipped.\n");
1109 /* older versions allowed to register SWC_DESKTOP and access it with FindWindowSW */
1110 ok(disp == NULL, "got %p\n", disp);
1111 ok(ret == 0, "got %d\n", ret);
1113 else {
1114 static const IID *browser_riids[] = {
1115 &IID_IWebBrowser2,
1116 &IID_NULL
1119 static const IID *viewdual_riids[] = {
1120 &IID_IShellFolderViewDual3,
1121 &IID_NULL
1124 IShellFolderViewDual *view;
1125 IShellBrowser *sb, *sb2;
1126 IServiceProvider *sp;
1127 IDispatch *doc, *app;
1128 IWebBrowser2 *wb;
1129 IShellView *sv;
1130 IUnknown *unk;
1132 ok(disp != NULL, "got %p\n", disp);
1133 ok(ret != HandleToUlong(hwnd), "got %d\n", ret);
1135 /* IDispatch-related tests */
1136 test_dispatch_typeinfo(disp, browser_riids);
1138 /* IWebBrowser2 */
1139 hr = IDispatch_QueryInterface(disp, &IID_IWebBrowser2, (void**)&wb);
1140 ok(hr == S_OK, "got 0x%08x\n", hr);
1142 hr = IWebBrowser2_Refresh(wb);
1143 todo_wine
1144 ok(hr == S_OK, "got 0x%08x\n", hr);
1146 hr = IWebBrowser2_get_Application(wb, &app);
1147 ok(hr == S_OK, "got 0x%08x\n", hr);
1148 ok(disp == app, "got %p, %p\n", app, disp);
1149 IDispatch_Release(app);
1151 hr = IWebBrowser2_get_Document(wb, &doc);
1152 todo_wine
1153 ok(hr == S_OK, "got 0x%08x\n", hr);
1154 if (hr == S_OK) {
1155 test_dispatch_typeinfo(doc, viewdual_riids);
1157 IWebBrowser2_Release(wb);
1159 /* IServiceProvider */
1160 hr = IDispatch_QueryInterface(disp, &IID_IShellFolderViewDual, (void**)&view);
1161 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
1163 hr = IDispatch_QueryInterface(disp, &IID_IServiceProvider, (void**)&sp);
1164 ok(hr == S_OK, "got 0x%08x\n", hr);
1166 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IShellBrowser, (void**)&sb);
1167 ok(hr == S_OK, "got 0x%08x\n", hr);
1169 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IShellBrowser, (void**)&sb2);
1170 ok(hr == S_OK, "got 0x%08x\n", hr);
1171 ok(sb == sb2, "got %p, %p\n", sb, sb2);
1173 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IOleWindow, (void**)&unk);
1174 ok(hr == S_OK, "got 0x%08x\n", hr);
1175 IUnknown_Release(unk);
1177 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IExplorerBrowser, (void**)&unk);
1178 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
1180 hr = IShellBrowser_QueryInterface(sb, &IID_IExplorerBrowser, (void**)&unk);
1181 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
1183 hr = IShellBrowser_QueryInterface(sb, &IID_IWebBrowser2, (void**)&unk);
1184 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
1186 hr = IShellBrowser_QueryInterface(sb, &IID_IDispatch, (void**)&unk);
1187 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
1189 hr = IShellBrowser_QueryActiveShellView(sb, &sv);
1190 ok(hr == S_OK, "got 0x%08x\n", hr);
1191 IShellView_Release(sv);
1193 IShellBrowser_Release(sb2);
1194 IShellBrowser_Release(sb);
1196 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IUnknown, (void**)&unk);
1197 ok(hr == S_OK, "got 0x%08x\n", hr);
1199 hr = IUnknown_QueryInterface(unk, &IID_IShellBrowser, (void**)&sb2);
1200 ok(hr == S_OK, "got 0x%08x\n", hr);
1201 IShellBrowser_Release(sb2);
1202 IUnknown_Release(unk);
1204 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IShellView, (void**)&sv);
1205 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
1207 IServiceProvider_Release(sp);
1208 IDispatch_Release(disp);
1211 disp = (void*)0xdeadbeef;
1212 ret = 0xdead;
1213 VariantInit(&v);
1214 hr = IShellWindows_FindWindowSW(shellwindows, &v, &v, SWC_DESKTOP, &ret, 0, &disp);
1215 ok(hr == S_OK || broken(hr == S_FALSE) /* winxp */, "got 0x%08x\n", hr);
1216 ok(disp == NULL, "got %p\n", disp);
1217 ok(ret != HandleToUlong(hwnd), "got %d\n", ret);
1219 disp = (void*)0xdeadbeef;
1220 ret = 0xdead;
1221 V_VT(&v) = VT_I4;
1222 V_I4(&v) = cookie;
1223 VariantInit(&v2);
1224 hr = IShellWindows_FindWindowSW(shellwindows, &v, &v2, SWC_BROWSER, &ret, SWFO_COOKIEPASSED, &disp);
1225 todo_wine
1226 ok(hr == S_FALSE, "got 0x%08x\n", hr);
1227 ok(disp == NULL, "got %p\n", disp);
1228 ok(ret == 0, "got %d\n", ret);
1230 hr = IShellWindows_Revoke(shellwindows, cookie);
1231 ok(hr == S_OK, "got 0x%08x\n", hr);
1232 DestroyWindow(hwnd);
1233 IShellWindows_Release(shellwindows);
1236 static void test_ParseName(void)
1238 static const WCHAR cadabraW[] = {'c','a','d','a','b','r','a',0};
1239 WCHAR pathW[MAX_PATH];
1240 IShellDispatch *sd;
1241 FolderItem *item;
1242 Folder *folder;
1243 HRESULT hr;
1244 VARIANT v;
1245 BSTR str;
1247 hr = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER,
1248 &IID_IShellDispatch, (void**)&sd);
1249 ok(hr == S_OK, "got 0x%08x\n", hr);
1251 GetTempPathW(ARRAY_SIZE(pathW), pathW);
1252 V_VT(&v) = VT_BSTR;
1253 V_BSTR(&v) = SysAllocString(pathW);
1254 hr = IShellDispatch_NameSpace(sd, v, &folder);
1255 ok(hr == S_OK, "got 0x%08x\n", hr);
1256 VariantClear(&v);
1258 item = (void*)0xdeadbeef;
1259 hr = Folder_ParseName(folder, NULL, &item);
1260 ok(hr == S_FALSE || broken(hr == E_INVALIDARG) /* win2k */, "got 0x%08x\n", hr);
1261 ok(item == NULL, "got %p\n", item);
1263 /* empty name */
1264 str = SysAllocStringLen(NULL, 0);
1265 item = (void*)0xdeadbeef;
1266 hr = Folder_ParseName(folder, str, &item);
1267 ok(hr == S_FALSE || broken(hr == E_INVALIDARG) /* win2k */, "got 0x%08x\n", hr);
1268 ok(item == NULL, "got %p\n", item);
1269 SysFreeString(str);
1271 /* path doesn't exist */
1272 str = SysAllocString(cadabraW);
1273 item = (void*)0xdeadbeef;
1274 hr = Folder_ParseName(folder, str, &item);
1275 ok(hr == S_FALSE || broken(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) /* win2k */,
1276 "got 0x%08x\n", hr);
1277 ok(item == NULL, "got %p\n", item);
1278 SysFreeString(str);
1280 lstrcatW(pathW, cadabraW);
1281 CreateDirectoryW(pathW, NULL);
1283 str = SysAllocString(cadabraW);
1284 item = NULL;
1285 hr = Folder_ParseName(folder, str, &item);
1286 ok(hr == S_OK, "got 0x%08x\n", hr);
1287 ok(item != NULL, "got %p\n", item);
1288 SysFreeString(str);
1290 hr = FolderItem_get_Path(item, &str);
1291 ok(hr == S_OK, "got 0x%08x\n", hr);
1292 ok(str[0] != 0, "path %s\n", wine_dbgstr_w(str));
1293 SysFreeString(str);
1295 RemoveDirectoryW(pathW);
1296 FolderItem_Release(item);
1297 Folder_Release(folder);
1298 IShellDispatch_Release(sd);
1301 static void test_Verbs(void)
1303 FolderItemVerbs *verbs, *verbs2;
1304 WCHAR pathW[MAX_PATH];
1305 FolderItemVerb *verb;
1306 IShellDispatch *sd;
1307 FolderItem *item;
1308 Folder2 *folder2;
1309 IDispatch *disp;
1310 Folder *folder;
1311 HRESULT hr;
1312 LONG count, i;
1313 VARIANT v;
1314 BSTR str;
1316 hr = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER,
1317 &IID_IShellDispatch, (void**)&sd);
1318 ok(hr == S_OK, "got 0x%08x\n", hr);
1320 GetTempPathW(ARRAY_SIZE(pathW), pathW);
1321 V_VT(&v) = VT_BSTR;
1322 V_BSTR(&v) = SysAllocString(pathW);
1323 hr = IShellDispatch_NameSpace(sd, v, &folder);
1324 ok(hr == S_OK, "got 0x%08x\n", hr);
1325 VariantClear(&v);
1327 hr = Folder_QueryInterface(folder, &IID_Folder2, (void**)&folder2);
1328 ok(hr == S_OK, "got 0x%08x\n", hr);
1329 Folder_Release(folder);
1331 hr = Folder2_get_Self(folder2, &item);
1332 ok(hr == S_OK, "got 0x%08x\n", hr);
1333 Folder2_Release(folder2);
1335 if (0) { /* crashes on some systems */
1336 hr = FolderItem_Verbs(item, NULL);
1337 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1339 hr = FolderItem_Verbs(item, &verbs);
1340 ok(hr == S_OK, "got 0x%08x\n", hr);
1342 hr = FolderItem_Verbs(item, &verbs2);
1343 ok(hr == S_OK, "got 0x%08x\n", hr);
1344 ok(verbs2 != verbs, "Unexpected verbs pointer.\n");
1345 FolderItemVerbs_Release(verbs2);
1347 disp = (void *)0xdeadbeef;
1348 hr = FolderItemVerbs_get_Application(verbs, &disp);
1349 ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
1350 ok(disp == NULL, "Unexpected application pointer.\n");
1352 disp = (void *)0xdeadbeef;
1353 hr = FolderItemVerbs_get_Parent(verbs, &disp);
1354 ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
1355 ok(disp == NULL, "Unexpected parent pointer %p.\n", disp);
1357 if (0) { /* crashes on winxp/win2k3 */
1358 hr = FolderItemVerbs_get_Count(verbs, NULL);
1359 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1361 count = 0;
1362 hr = FolderItemVerbs_get_Count(verbs, &count);
1363 ok(hr == S_OK, "got 0x%08x\n", hr);
1364 ok(count > 0, "got count %d\n", count);
1366 if (0) { /* crashes on winxp/win2k3 */
1367 V_VT(&v) = VT_I4;
1368 V_I4(&v) = 0;
1369 hr = FolderItemVerbs_Item(verbs, v, NULL);
1370 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1372 /* there's always one item more, so you can access [0,count],
1373 instead of actual [0,count) */
1374 for (i = 0; i <= count; i++) {
1375 V_VT(&v) = VT_I4;
1376 V_I4(&v) = i;
1377 hr = FolderItemVerbs_Item(verbs, v, &verb);
1378 ok(hr == S_OK, "got 0x%08x\n", hr);
1379 hr = FolderItemVerb_get_Name(verb, &str);
1380 ok(hr == S_OK, "got 0x%08x\n", hr);
1381 ok(str != NULL, "%d: name %s\n", i, wine_dbgstr_w(str));
1382 if (i == count)
1383 ok(str[0] == 0, "%d: got terminating item %s\n", i, wine_dbgstr_w(str));
1385 disp = (void *)0xdeadbeef;
1386 hr = FolderItemVerb_get_Parent(verb, &disp);
1387 ok(hr == E_NOTIMPL, "got %#x.\n", hr);
1388 ok(disp == NULL, "Unexpected parent pointer %p.\n", disp);
1390 disp = (void *)0xdeadbeef;
1391 hr = FolderItemVerb_get_Application(verb, &disp);
1392 ok(hr == E_NOTIMPL, "got %#x.\n", hr);
1393 ok(disp == NULL, "Unexpected parent pointer %p.\n", disp);
1395 SysFreeString(str);
1396 FolderItemVerb_Release(verb);
1399 V_VT(&v) = VT_I4;
1400 V_I4(&v) = count+1;
1401 verb = NULL;
1402 hr = FolderItemVerbs_Item(verbs, v, &verb);
1403 ok(hr == S_OK, "got 0x%08x\n", hr);
1404 ok(verb == NULL, "got %p\n", verb);
1406 FolderItemVerbs_Release(verbs);
1407 FolderItem_Release(item);
1408 IShellDispatch_Release(sd);
1411 static void test_ShellLinkObject(void)
1413 HRESULT hr;
1414 IShellDispatch *sd;
1415 WCHAR path[MAX_PATH],
1416 empty_path[MAX_PATH],
1417 link_path[MAX_PATH];
1418 VARIANT v;
1419 Folder2 *folder2;
1420 Folder *folder;
1421 FolderItem *item;
1422 IDispatch *dispatch;
1423 IShellLinkW *sl;
1424 IShellLinkDual2* sld;
1425 IPersistFile *pf;
1426 BOOL ret;
1427 BSTR str;
1428 HANDLE file;
1429 int hk;
1431 hr = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER,
1432 &IID_IShellDispatch, (void**)&sd);
1433 ok(hr == S_OK, "got 0x%08x\n", hr);
1435 GetTempPathW(MAX_PATH, path);
1436 V_VT(&v) = VT_BSTR;
1437 V_BSTR(&v) = SysAllocString(path);
1438 hr = IShellDispatch_NameSpace(sd, v, &folder);
1439 ok(hr == S_OK, "got 0x%08x\n", hr);
1440 VariantClear(&v);
1442 hr = Folder_QueryInterface(folder, &IID_Folder2, (void**)&folder2);
1443 ok(hr == S_OK, "got 0x%08x\n", hr);
1444 Folder_Release(folder);
1446 hr = Folder2_get_Self(folder2, &item);
1447 ok(hr == S_OK, "got 0x%08x\n", hr);
1449 dispatch = (IDispatch*)0xdeadbeef;
1450 hr = FolderItem_get_GetLink(item, &dispatch);
1451 ok(hr == E_NOTIMPL, "got 0x%08x\n", hr);
1452 ok(dispatch == NULL, "got %p\n", dispatch);
1454 FolderItem_Release(item);
1456 PathCombineW(empty_path, path, L"winetest_empty_file.txt");
1457 file = CreateFileW(empty_path, 0, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1458 ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %08x\n", GetLastError());
1459 CloseHandle(file);
1461 hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (LPVOID*)&sl);
1462 ok(hr == S_OK, "got 0x%08x\n", hr);
1463 hr = IShellLinkW_SetPath(sl, empty_path);
1464 ok(hr == S_OK, "got 0x%08x\n", hr);
1465 hr = IShellLinkW_GetPath(sl, empty_path, MAX_PATH, NULL, 0);
1466 ok(hr == S_OK, "got 0x%08x\n", hr);
1467 hr = IShellLinkW_SetDescription(sl, L"description");
1468 ok(hr == S_OK, "got 0x%08x\n", hr);
1469 hr = IShellLinkW_SetWorkingDirectory(sl, L"working directory");
1470 ok(hr == S_OK, "got 0x%08x\n", hr);
1471 hr = IShellLinkW_SetArguments(sl, L"arguments");
1472 ok(hr == S_OK, "got 0x%08x\n", hr);
1473 hr = IShellLinkW_SetHotkey(sl, 1234);
1474 ok(hr == S_OK, "got 0x%08x\n", hr);
1475 hr = IShellLinkW_SetShowCmd(sl, 1);
1476 ok(hr == S_OK, "got 0x%08x\n", hr);
1478 hr = IShellLinkW_QueryInterface(sl, &IID_IPersistFile, (LPVOID*)&pf);
1479 ok(hr == S_OK, "got 0x%08x\n", hr);
1481 PathCombineW(link_path, path, L"winetest_filled.lnk");
1482 hr = IPersistFile_Save(pf, link_path, TRUE);
1483 ok(hr == S_OK, "got 0x%08x\n", hr);
1485 IPersistFile_Release(pf);
1486 IShellLinkW_Release(sl);
1488 str = SysAllocString(L"winetest_filled.lnk");
1489 hr = Folder2_ParseName(folder2, str, &item);
1490 ok(hr == S_OK, "got 0x%08x\n", hr);
1491 SysFreeString(str);
1493 dispatch = NULL;
1494 hr = FolderItem_get_GetLink(item, &dispatch);
1495 ok(hr == S_OK, "got 0x%08x\n", hr);
1496 ok(dispatch != NULL, "got %p\n", dispatch);
1498 if (dispatch) {
1499 sld = (IShellLinkDual2*)dispatch;
1501 str = NULL;
1502 hr = IShellLinkDual2_get_Path(sld, &str);
1503 ok(hr == S_OK, "got 0x%08x\n", hr);
1504 if (hr == S_OK) {
1505 ok(!wcscmp(str, empty_path), "got %s (wanted %s)\n",
1506 wine_dbgstr_w(str), wine_dbgstr_w(empty_path));
1507 SysFreeString(str);
1510 str = NULL;
1511 hr = IShellLinkDual2_get_Description(sld, &str);
1512 todo_wine ok(hr == S_OK, "got 0x%08x\n", hr);
1513 if (hr == S_OK) {
1514 ok(!wcscmp(str, L"description"), "got %s\n", wine_dbgstr_w(str));
1515 SysFreeString(str);
1518 str = NULL;
1519 hr = IShellLinkDual2_get_WorkingDirectory(sld, &str);
1520 todo_wine ok(hr == S_OK, "got 0x%08x\n", hr);
1521 if (hr == S_OK) {
1522 ok(!wcscmp(str, L"working directory"), "got %s\n", wine_dbgstr_w(str));
1523 SysFreeString(str);
1526 str = NULL;
1527 hr = IShellLinkDual2_get_Arguments(sld, &str);
1528 todo_wine ok(hr == S_OK, "got 0x%08x\n", hr);
1529 if (hr == S_OK) {
1530 ok(!wcscmp(str, L"arguments"), "got %s\n", wine_dbgstr_w(str));
1531 SysFreeString(str);
1534 hk = 0;
1535 hr = IShellLinkDual2_get_Hotkey(sld, &hk);
1536 todo_wine ok(hr == S_OK, "got 0x%08x\n", hr);
1537 todo_wine ok(hk == 1234, "got %i\n", hk);
1539 hk = 0;
1540 hr = IShellLinkDual2_get_ShowCommand(sld, &hk);
1541 todo_wine ok(hr == S_OK, "got 0x%08x\n", hr);
1542 todo_wine ok(hk == 1, "got %i\n", hk);
1544 IShellLinkDual2_Release(sld);
1547 FolderItem_Release(item);
1549 ret = DeleteFileW(link_path);
1550 ok(ret, "DeleteFile failed: %08x\n", GetLastError());
1551 ret = DeleteFileW(empty_path);
1552 ok(ret, "DeleteFile failed: %08x\n", GetLastError());
1554 Folder2_Release(folder2);
1556 IShellDispatch_Release(sd);
1559 static void test_ShellExecute(void)
1561 HRESULT hr;
1562 IShellDispatch2 *sd;
1563 BSTR name;
1564 VARIANT args, dir, op, show;
1566 static const WCHAR regW[] = {'r','e','g',0};
1568 hr = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER,
1569 &IID_IShellDispatch2, (void**)&sd);
1570 if (hr != S_OK)
1572 win_skip("IShellDispatch2 not supported\n");
1573 return;
1576 VariantInit(&args);
1577 VariantInit(&dir);
1578 VariantInit(&op);
1579 VariantInit(&show);
1581 V_VT(&show) = VT_I4;
1582 V_I4(&show) = 0;
1584 name = SysAllocString(regW);
1586 hr = IShellDispatch2_ShellExecute(sd, name, args, dir, op, show);
1587 ok(hr == S_OK, "ShellExecute failed: %08x\n", hr);
1589 /* test invalid value for show */
1590 V_VT(&show) = VT_BSTR;
1591 V_BSTR(&show) = name;
1593 hr = IShellDispatch2_ShellExecute(sd, name, args, dir, op, show);
1594 ok(hr == S_OK, "ShellExecute failed: %08x\n", hr);
1596 SysFreeString(name);
1597 IShellDispatch2_Release(sd);
1600 START_TEST(shelldispatch)
1602 HRESULT r;
1604 r = CoInitialize(NULL);
1605 ok(SUCCEEDED(r), "CoInitialize failed: %08x\n", r);
1606 if (FAILED(r))
1607 return;
1609 init_function_pointers();
1610 test_namespace();
1611 test_items();
1612 test_service();
1613 test_ShellFolderViewDual();
1614 test_ShellWindows();
1615 test_ParseName();
1616 test_Verbs();
1617 test_ShellLinkObject();
1618 test_ShellExecute();
1620 CoUninitialize();