1 /*
2  * Unit tests for IShellDispatch
3  *
4  * Copyright 2010 Alexander Morozov for Etersoft
5  *
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.
10  *
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.
15  *
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
19  */
20 
21 #define COBJMACROS
22 #define NONAMELESSUNION
23 #define NONAMELESSSTRUCT
24 
25 #include "shldisp.h"
26 #include "shlobj.h"
27 #include "shlwapi.h"
28 #include "winsvc.h"
29 
30 #include "wine/heap.h"
31 #include "wine/test.h"
32 
33 #include "initguid.h"
34 
35 #define EXPECT_HR(hr,hr_exp) \
36     ok(hr == hr_exp, "got 0x%08x, expected 0x%08x\n", hr, hr_exp)
37 
38 #define EXPECT_REF(obj,ref) _expect_ref((IUnknown *)obj, ref, __LINE__)
39 static void _expect_ref(IUnknown *obj, ULONG ref, int line)
40 {
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);
45 }
46 
47 static const WCHAR winetestW[] = {'w','i','n','e','t','e','s','t',0};
48 
49 static HRESULT (WINAPI *pSHGetNameFromIDList)(PCIDLIST_ABSOLUTE,SIGDN,PWSTR*);
50 
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);
53 
54 static BSTR a2bstr(const char *str)
55 {
56     BSTR ret;
57     int len;
58 
59     len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
60     ret = SysAllocStringLen(NULL, len);
61     MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
62 
63     return ret;
64 }
65 
66 static void variant_set_string(VARIANT *v, const char *s)
67 {
68     V_VT(v) = VT_BSTR;
69     V_BSTR(v) = a2bstr(s);
70 }
71 
72 static void init_function_pointers(void)
73 {
74     HMODULE hshell32;
75 
76     hshell32 = GetModuleHandleA("shell32.dll");
77     pSHGetNameFromIDList = (void*)GetProcAddress(hshell32, "SHGetNameFromIDList");
78 }
79 
80 static void test_namespace(void)
81 {
82     static const ShellSpecialFolderConstants special_folders[] =
83     {
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,
122     };
123 
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};
129 
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;
141 
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);
144 
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);
150 
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);
156 
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);
162 
163     /* test valid folder ids */
164     for (i = 0; i < sizeof(special_folders)/sizeof(special_folders[0]); i++)
165     {
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);
177     }
178 
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);
185 
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)
191     {
192         static WCHAR path[MAX_PATH];
193 
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);
196 
197         r = Folder_get_Title(folder, &title);
198         ok(r == S_OK, "Folder::get_Title failed: %08x\n", r);
199         if (r == S_OK)
200         {
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)
206             {
207                 LPITEMIDLIST pidl;
208                 PWSTR name;
209 
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);
217             }
218             else
219             {
220                 WCHAR *p;
221 
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));
227             }
228             SysFreeString(title);
229         }
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)
233         {
234             r = Folder2_get_Self(folder2, &item);
235             ok(r == S_OK, "Folder::get_Self failed: %08x\n", r);
236             if (r == S_OK)
237             {
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);
243             }
244             Folder2_Release(folder2);
245         }
246         Folder_Release(folder);
247     }
248 
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);
253 
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));
262 
263     SysFreeString(item_path);
264     FolderItem_Release(item);
265     Folder2_Release(folder2);
266     Folder_Release(folder);
267 
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));
277 
278     GetFullPathNameW(winetestW, MAX_PATH, tempW, NULL);
279 
280     len = GetLongPathNameW(tempW, NULL, 0);
281     long_pathW = heap_alloc(len * sizeof(WCHAR));
282     GetLongPathNameW(tempW, long_pathW, len);
283 
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);
288 
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);
293 
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);
298 
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);
309 
310     Folder_Release(folder);
311     VariantClear(&var);
312 
313     len = lstrlenW(tempW);
314     if (len < MAX_PATH - 1)
315     {
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)
322         {
323             r = Folder_get_Title(folder, &title);
324             ok(r == S_OK, "Folder::get_Title failed: %08x\n", r);
325             if (r == S_OK)
326             {
327                 ok(!lstrcmpW(title, winetestW), "bad title: %s\n",
328                  wine_dbgstr_w(title));
329                 SysFreeString(title);
330             }
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)
334             {
335                 r = Folder2_get_Self(folder2, &item);
336                 ok(r == S_OK, "Folder::get_Self failed: %08x\n", r);
337                 if (r == S_OK)
338                 {
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);
345                 }
346                 Folder2_Release(folder2);
347             }
348             Folder_Release(folder);
349         }
350         SysFreeString(V_BSTR(&var));
351     }
352 
353     heap_free(long_pathW);
354     RemoveDirectoryW(winetestW);
355     SetCurrentDirectoryW(curW);
356     IShellDispatch_Release(sd);
357 }
358 
359 static void test_items(void)
360 {
361     static const struct
362     {
363         char name[32];
364         enum
365         {
366             DIRECTORY,
367             EMPTY_FILE,
368         }
369         type;
370     }
371     file_defs[] =
372     {
373         { "00-Myfolder",        DIRECTORY  },
374         { "01-empty.bin",       EMPTY_FILE },
375     };
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, 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;
394 
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");
398 
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);
408 
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);
415 
416     VariantClear(&var);
417     SetCurrentDirectoryW(winetestW);
418     GetCurrentDirectoryW(MAX_PATH, path);
419     GetLongPathNameW(path, cur_dir, MAX_PATH);
420 
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);
428 
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);
435 
436     FolderItems_AddRef(items);
437     EXPECT_REF(folder, 2);
438     FolderItems_Release(items);
439 
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);
447 
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);
453 
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);
458 
459     if (0) /* crashes on all versions of Windows */
460         r = FolderItems_get_Count(items, NULL);
461 
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);
465 
466     V_VT(&var) = VT_I4;
467     V_I4(&var) = 0;
468 
469     if (0) /* crashes on all versions of Windows */
470         r = FolderItems_Item(items, var, NULL);
471 
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");
475 
476     /* create test files */
477     for (i = 0; i < sizeof(file_defs)/sizeof(file_defs[0]); i++)
478     {
479         switch (file_defs[i].type)
480         {
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;
489 
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;
495         }
496     }
497 
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);
503 
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");
510 
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);
515 
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);
520 
521     if (item) FolderItem_Release(item);
522     VariantClear(&var);
523 
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)
533     {
534         ok(!!items2, "items2 is null\n");
535         FolderItems2_Release(items2);
536     }
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");
540 
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 == sizeof(file_defs)/sizeof(file_defs[0]),
545        "expected %d files, got %d\n", (LONG)(sizeof(file_defs)/sizeof(file_defs[0])), count);
546 
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");
552 
553     V_VT(&var) = VT_I2;
554     V_I2(&var) = 0;
555 
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: %08x\n", r);
561     ok(!!item, "item is null\n");
562     EXPECT_REF(folder, 3);
563     EXPECT_REF(items, 2);
564 
565     r = Folder_get_Application(folder, &disp);
566     ok(r == S_OK, "Failed to get application pointer %#x.\n", r);
567     r = FolderItem_get_Application(item, &disp2);
568     ok(r == S_OK, "Failed to get application pointer %#x.\n", r);
569     ok(disp == disp2, "Unexpected application pointer.\n");
570     IDispatch_Release(disp2);
571     IDispatch_Release(disp);
572 
573     FolderItem_Release(item);
574 
575     V_VT(&var) = VT_I4;
576     V_I4(&var) = 0;
577     item = NULL;
578     r = FolderItems_Item(items, var, &item);
579     ok(r == S_OK, "FolderItems::Item failed: %08x\n", r);
580     ok(!!item, "item is null\n");
581     if (item) FolderItem_Release(item);
582 
583     V_I4(&var) = -1;
584     item = (FolderItem*)0xdeadbeef;
585     r = FolderItems_Item(items, var, &item);
586     ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r);
587     ok(!item, "item is not null\n");
588 
589     V_VT(&var) = VT_ERROR;
590     V_ERROR(&var) = 0;
591     item = NULL;
592     r = FolderItems_Item(items, var, &item);
593     ok(r == S_OK, "expected S_OK, got %08x\n", r);
594     ok(!!item, "item is null\n");
595     if (item)
596     {
597         bstr = NULL;
598         r = FolderItem_get_Path(item, &bstr);
599         ok(r == S_OK, "FolderItem::get_Path failed: %08x\n", r);
600         ok(!lstrcmpW(bstr, cur_dir),
601            "expected %s, got %s\n", wine_dbgstr_w(cur_dir), wine_dbgstr_w(bstr));
602         SysFreeString(bstr);
603         FolderItem_Release(item);
604     }
605 
606     V_VT(&int_index) = VT_I4;
607 
608     /* test the folder item corresponding to each file */
609     for (i = 0; i < sizeof(file_defs)/sizeof(file_defs[0]); i++)
610     {
611         VARIANT_BOOL b;
612         BSTR name;
613 
614         V_I4(&int_index) = i;
615         variant_set_string(&str_index, file_defs[i].name);
616 
617         item = NULL;
618         r = FolderItems_Item(items, int_index, &item);
619         ok(r == S_OK, "file_defs[%d]: FolderItems::Item failed: %08x\n", i, r);
620         ok(!!item, "file_defs[%d]: item is null\n", i);
621 
622         item2 = NULL;
623         r = FolderItems_Item(items, int_index, &item2);
624         ok(r == S_OK, "file_defs[%d]: FolderItems::Item failed: %08x\n", i, r);
625         ok(item2 != item, "file_defs[%d]: item and item2 are the same\n", i);
626         FolderItem_Release(item2);
627 
628         bstr = NULL;
629         r = FolderItem_get_Path(item, &bstr);
630         ok(r == S_OK, "file_defs[%d]: FolderItem::get_Path failed: %08x\n", i, r);
631         PathCombineW(path, cur_dir, V_BSTR(&str_index));
632         ok(!lstrcmpW(bstr, path),
633            "file_defs[%d]: expected %s, got %s\n", i, wine_dbgstr_w(path), wine_dbgstr_w(bstr));
634         SysFreeString(bstr);
635 
636         bstr = a2bstr(file_defs[i].name);
637         r = FolderItem_get_Name(item, &name);
638         ok(r == S_OK, "Failed to get item name, hr %#x.\n", r);
639         /* Returned display name does not have to strictly match file name, e.g. extension could be omitted. */
640         ok(lstrlenW(name) <= lstrlenW(bstr), "file_defs[%d]: unexpected name length.\n", i);
641         ok(!memcmp(bstr, name, lstrlenW(name) * sizeof(WCHAR)), "file_defs[%d]: unexpected name %s.\n", i, wine_dbgstr_w(name));
642         SysFreeString(name);
643         SysFreeString(bstr);
644 
645         FolderItem_Release(item);
646 
647         item = NULL;
648         r = FolderItems_Item(items, str_index, &item);
649         ok(r == S_OK, "file_defs[%d]: FolderItems::Item failed: %08x\n", i, r);
650         ok(!!item, "file_defs[%d]: item is null\n", i);
651 
652         bstr = NULL;
653         r = FolderItem_get_Path(item, &bstr);
654         ok(r == S_OK, "file_defs[%d]: FolderItem::get_Path failed: %08x\n", i, r);
655         PathCombineW(path, cur_dir, V_BSTR(&str_index));
656         ok(!lstrcmpW(bstr, path),
657            "file_defs[%d]: expected %s, got %s\n", i, wine_dbgstr_w(path), wine_dbgstr_w(bstr));
658         SysFreeString(bstr);
659 
660         b = 0xdead;
661         r = FolderItem_get_IsFolder(item, &b);
662         ok(r == S_OK, "Failed to get IsFolder property, %#x.\n", r);
663         ok(file_defs[i].type == DIRECTORY ? b == VARIANT_TRUE : b == VARIANT_FALSE, "Unexpected prop value %#x.\n", b);
664 
665         FolderItem_Release(item);
666 
667         if (file_defs[i].type == DIRECTORY)
668         {
669             /* test that getting an item object for a file in a subdirectory succeeds */
670             PathCombineA(cstr, file_defs[i].name, "foo.txt");
671             variant_set_string(&str_index2, cstr);
672             item2 = NULL;
673             r = FolderItems_Item(items, str_index2, &item2);
674             ok(r == S_OK, "file_defs[%d]: FolderItems::Item failed: %08x\n", i, r);
675             ok(!!item2, "file_defs[%d]: item is null\n", i);
676             if (item2) FolderItem_Release(item2);
677             VariantClear(&str_index2);
678 
679             /* delete the file in the subdirectory */
680             ret = DeleteFileA(cstr);
681             ok(ret, "file_defs[%d]: DeleteFile failed: %08x\n", i, GetLastError());
682 
683             /* test that getting an item object via a relative path fails */
684             strcpy(cstr, file_defs[i].name);
685             strcat(cstr, "\\..\\");
686             strcat(cstr, file_defs[i].name);
687             variant_set_string(&str_index2, cstr);
688             item2 = (FolderItem*)0xdeadbeef;
689             r = FolderItems_Item(items, str_index2, &item2);
690        todo_wine {
691             ok(r == S_FALSE, "file_defs[%d]: expected S_FALSE, got %08x\n", i, r);
692             ok(!item2, "file_defs[%d]: item is not null\n", i);
693        }
694             if (item2) FolderItem_Release(item2);
695             VariantClear(&str_index2);
696 
697             /* remove the directory */
698             ret = RemoveDirectoryA(file_defs[i].name);
699             ok(ret, "file_defs[%d]: RemoveDirectory failed: %08x\n", i, GetLastError());
700         }
701         else
702         {
703             ret = DeleteFileA(file_defs[i].name);
704             ok(ret, "file_defs[%d]: DeleteFile failed: %08x\n", i, GetLastError());
705         }
706 
707         /* test that the folder item is still accessible by integer index */
708         item = NULL;
709         r = FolderItems_Item(items, int_index, &item);
710         ok(r == S_OK, "file_defs[%d]: FolderItems::Item failed: %08x\n", i, r);
711         ok(!!item, "file_defs[%d]: item is null\n", i);
712 
713         bstr = NULL;
714         r = FolderItem_get_Path(item, &bstr);
715         ok(r == S_OK, "file_defs[%d]: FolderItem::get_Path failed: %08x\n", i, r);
716         PathCombineW(path, cur_dir, V_BSTR(&str_index));
717         ok(!lstrcmpW(bstr, path),
718            "file_defs[%d]: expected %s, got %s\n", i, wine_dbgstr_w(path), wine_dbgstr_w(bstr));
719         SysFreeString(bstr);
720 
721         FolderItem_Release(item);
722 
723         /* test that the folder item is no longer accessible by string index */
724         item = (FolderItem*)0xdeadbeef;
725         r = FolderItems_Item(items, str_index, &item);
726         ok(r == S_FALSE, "file_defs[%d]: expected S_FALSE, got %08x\n", i, r);
727         ok(!item, "file_defs[%d]: item is not null\n", i);
728 
729         VariantClear(&str_index);
730     }
731 
732     /* test that there are only as many folder items as there were files */
733     V_I4(&int_index) = sizeof(file_defs)/sizeof(file_defs[0]);
734     item = (FolderItem*)0xdeadbeef;
735     r = FolderItems_Item(items, int_index, &item);
736     ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r);
737     ok(!item, "item is not null\n");
738 
739     if (0) /* crashes on xp */
740     {
741         r = FolderItems_get_Application(items, NULL);
742         ok(r == E_INVALIDARG, "expected E_INVALIDARG, got %08x\n", r);
743     }
744 
745     r = FolderItems_get_Application(items, &disp);
746     ok(r == S_OK, "FolderItems::get_Application failed: %08x\n", r);
747 
748     r = Folder_get_Application(folder, &disp2);
749     ok(r == S_OK, "Failed to get application pointer, hr %#x.\n", r);
750     ok(disp == disp2, "Unexpected application pointer.\n");
751     IDispatch_Release(disp2);
752     IDispatch_Release(disp);
753 
754     if (0) /* crashes on xp */
755     {
756         r = FolderItems_get_Parent(items, NULL);
757         ok(r == E_NOTIMPL, "expected E_NOTIMPL, got %08x\n", r);
758     }
759 
760     disp = (IDispatch*)0xdeadbeef;
761     r = FolderItems_get_Parent(items, &disp);
762     ok(r == E_NOTIMPL, "expected E_NOTIMPL, got %08x\n", r);
763     ok(!disp, "disp is not null\n");
764 
765     if (0) /* crashes on xp */
766     {
767         r = FolderItems__NewEnum(items, NULL);
768         ok(r == E_INVALIDARG, "expected E_INVALIDARG, got %08x\n", r);
769     }
770 
771     r = FolderItems__NewEnum(items, &unk);
772 todo_wine
773     ok(r == S_OK, "FolderItems::_NewEnum failed: %08x\n", r);
774 todo_wine
775     ok(!!unk, "unk is null\n");
776     if (unk) IUnknown_Release(unk);
777 
778     if (items3)
779     {
780         r = FolderItems3_Filter(items3, 0, NULL);
781 todo_wine
782         ok(r == S_OK, "expected S_OK, got %08x\n", r);
783 
784         if (0) /* crashes on xp */
785         {
786             r = FolderItems3_get_Verbs(items3, NULL);
787             ok(r == E_INVALIDARG, "expected E_INVALIDARG, got %08x\n", r);
788         }
789 
790         r = FolderItems3_get_Verbs(items3, &verbs);
791 todo_wine
792         ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r);
793         ok(!verbs, "verbs is not null\n");
794     }
795 
796     /* remove the temporary directory and restore the original working directory */
797     GetTempPathW(MAX_PATH, path);
798     SetCurrentDirectoryW(path);
799     ret = RemoveDirectoryW(winetestW);
800     ok(ret, "RemoveDirectory failed: %08x\n", GetLastError());
801     SetCurrentDirectoryW(orig_dir);
802 
803     /* test that everything stops working after the directory has been removed */
804     count = -1;
805     r = FolderItems_get_Count(items, &count);
806     ok(r == S_OK, "FolderItems::get_Count failed: %08x\n", r);
807     ok(!count, "expected 0 files, got %d\n", count);
808 
809     item = NULL;
810     V_I4(&int_index) = 0;
811     item = (FolderItem*)0xdeadbeef;
812     r = FolderItems_Item(items, int_index, &item);
813     ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r);
814     ok(!item, "item is not null\n");
815 
816     variant_set_string(&str_index, file_defs[0].name);
817     item = (FolderItem*)0xdeadbeef;
818     r = FolderItems_Item(items, str_index, &item);
819     ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r);
820     ok(!item, "item is not null\n");
821     VariantClear(&str_index);
822 
823     FolderItems_Release(items);
824     Folder_Release(folder);
825     if (items3) FolderItems3_Release(items3);
826     IShellDispatch_Release(sd);
827 }
828 
829 static void test_service(void)
830 {
831     static const WCHAR spooler[] = {'S','p','o','o','l','e','r',0};
832     static const WCHAR dummyW[] = {'d','u','m','m','y',0};
833     SERVICE_STATUS_PROCESS status;
834     SC_HANDLE scm, service;
835     IShellDispatch2 *sd;
836     DWORD dummy;
837     HRESULT hr;
838     BSTR name;
839     VARIANT v;
840 
841     hr = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER,
842         &IID_IShellDispatch2, (void**)&sd);
843     if (hr != S_OK)
844     {
845         win_skip("IShellDispatch2 not supported\n");
846         return;
847     }
848 
849     V_VT(&v) = VT_I2;
850     V_I2(&v) = 10;
851     hr = IShellDispatch2_IsServiceRunning(sd, NULL, &v);
852     ok(V_VT(&v) == VT_BOOL, "got %d\n", V_VT(&v));
853     ok(V_BOOL(&v) == VARIANT_FALSE, "got %d\n", V_BOOL(&v));
854     EXPECT_HR(hr, S_OK);
855 
856     scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
857     service = OpenServiceW(scm, spooler, SERVICE_QUERY_STATUS);
858     QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy);
859     CloseServiceHandle(service);
860     CloseServiceHandle(scm);
861 
862     /* service should exist */
863     name = SysAllocString(spooler);
864     V_VT(&v) = VT_I2;
865     hr = IShellDispatch2_IsServiceRunning(sd, name, &v);
866     EXPECT_HR(hr, S_OK);
867     ok(V_VT(&v) == VT_BOOL, "got %d\n", V_VT(&v));
868     if (status.dwCurrentState == SERVICE_RUNNING)
869         ok(V_BOOL(&v) == VARIANT_TRUE, "got %d\n", V_BOOL(&v));
870     else
871         ok(V_BOOL(&v) == VARIANT_FALSE, "got %d\n", V_BOOL(&v));
872     SysFreeString(name);
873 
874     /* service doesn't exist */
875     name = SysAllocString(dummyW);
876     V_VT(&v) = VT_I2;
877     hr = IShellDispatch2_IsServiceRunning(sd, name, &v);
878     EXPECT_HR(hr, S_OK);
879     ok(V_VT(&v) == VT_BOOL, "got %d\n", V_VT(&v));
880     ok(V_BOOL(&v) == VARIANT_FALSE, "got %d\n", V_BOOL(&v));
881     SysFreeString(name);
882 
883     IShellDispatch2_Release(sd);
884 }
885 
886 static void test_dispatch_typeinfo(IDispatch *disp, REFIID *riid)
887 {
888     ITypeInfo *typeinfo;
889     TYPEATTR *typeattr;
890     UINT count;
891     HRESULT hr;
892 
893     count = 10;
894     hr = IDispatch_GetTypeInfoCount(disp, &count);
895     ok(hr == S_OK, "got 0x%08x\n", hr);
896     ok(count == 1, "got %u\n", count);
897 
898     hr = IDispatch_GetTypeInfo(disp, 0, LOCALE_SYSTEM_DEFAULT, &typeinfo);
899     ok(hr == S_OK, "got 0x%08x\n", hr);
900 
901     hr = ITypeInfo_GetTypeAttr(typeinfo, &typeattr);
902     ok(hr == S_OK, "got 0x%08x\n", hr);
903     while (!IsEqualGUID(*riid, &IID_NULL)) {
904         if (IsEqualGUID(&typeattr->guid, *riid))
905             break;
906         riid++;
907     }
908     ok(IsEqualGUID(&typeattr->guid, *riid), "unexpected type guid %s\n", wine_dbgstr_guid(&typeattr->guid));
909 
910     ITypeInfo_ReleaseTypeAttr(typeinfo, typeattr);
911     ITypeInfo_Release(typeinfo);
912 }
913 
914 static void test_ShellFolderViewDual(void)
915 {
916     static const IID *shelldisp_riids[] = {
917         &IID_IShellDispatch6,
918         &IID_IShellDispatch5,
919         &IID_IShellDispatch4,
920         &IID_IShellDispatch2,
921         &IID_IWin7ShellDispatch6,
922         &IID_NULL
923     };
924     IShellFolderViewDual *viewdual;
925     IShellFolder *desktop, *tmpdir;
926     IShellView *view, *view2;
927     IDispatch *disp, *disp2;
928     WCHAR pathW[MAX_PATH];
929     LPITEMIDLIST pidl;
930     HRESULT hr;
931 
932     /* IShellFolderViewDual is not an IShellView extension */
933     hr = SHGetDesktopFolder(&desktop);
934     ok(hr == S_OK, "got 0x%08x\n", hr);
935 
936     hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
937     ok(hr == S_OK, "got 0x%08x\n", hr);
938 
939     hr = IShellView_QueryInterface(view, &IID_IShellFolderViewDual, (void**)&viewdual);
940     ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
941 
942     hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IDispatch, (void**)&disp);
943     ok(hr == S_OK, "got 0x%08x\n", hr);
944 
945     hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IDispatch, (void**)&disp2);
946     ok(hr == S_OK, "got 0x%08x\n", hr);
947     ok(disp2 == disp, "got %p, %p\n", disp2, disp);
948     IDispatch_Release(disp2);
949 
950     hr = IDispatch_QueryInterface(disp, &IID_IShellFolderViewDual, (void**)&viewdual);
951     ok(hr == S_OK, "got 0x%08x\n", hr);
952     ok(disp == (IDispatch*)viewdual, "got %p, expected %p\n", viewdual, disp);
953 
954     hr = IShellFolderViewDual_QueryInterface(viewdual, &IID_IShellView, (void**)&view2);
955     ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
956 
957     /* get_Application() */
958 
959 if (0) /* crashes on pre-vista */ {
960     hr = IShellFolderViewDual_get_Application(viewdual, NULL);
961     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
962 }
963     hr = IShellFolderViewDual_get_Application(viewdual, &disp2);
964     ok(hr == S_OK, "got 0x%08x\n", hr);
965     ok(disp2 != (IDispatch*)viewdual, "got %p, %p\n", disp2, viewdual);
966     test_dispatch_typeinfo(disp2, shelldisp_riids);
967     IDispatch_Release(disp2);
968 
969     IShellFolderViewDual_Release(viewdual);
970     IDispatch_Release(disp);
971 
972     disp = (void*)0xdeadbeef;
973     hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IShellFolderViewDual, (void**)&disp);
974     ok(hr == E_NOINTERFACE || broken(hr == E_NOTIMPL) /* win2k */, "got 0x%08x\n", hr);
975     ok(disp == NULL, "got %p\n", disp);
976     IShellView_Release(view);
977 
978     /* Try with some other folder, that's not a desktop */
979     GetTempPathW(sizeof(pathW)/sizeof(pathW[0]), pathW);
980     hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, pathW, NULL, &pidl, NULL);
981     ok(hr == S_OK, "got 0x%08x\n", hr);
982 
983     hr = IShellFolder_BindToObject(desktop, pidl, NULL, &IID_IShellFolder, (void**)&tmpdir);
984     ok(hr == S_OK, "got 0x%08x\n", hr);
985     CoTaskMemFree(pidl);
986 
987     hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
988     ok(hr == S_OK, "got 0x%08x\n", hr);
989 
990     hr = IShellView_QueryInterface(view, &IID_IShellFolderViewDual, (void**)&viewdual);
991     ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
992 
993     hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IDispatch, (void**)&disp);
994     ok(hr == S_OK, "got 0x%08x\n", hr);
995     IDispatch_Release(disp);
996     IShellView_Release(view);
997 
998     IShellFolder_Release(tmpdir);
999     IShellFolder_Release(desktop);
1000 }
1001 
1002 static void test_ShellWindows(void)
1003 {
1004     IShellWindows *shellwindows;
1005     LONG cookie, cookie2, ret;
1006     IDispatch *disp;
1007     VARIANT v, v2;
1008     HRESULT hr;
1009     HWND hwnd;
1010 
1011     hr = CoCreateInstance(&CLSID_ShellWindows, NULL, CLSCTX_LOCAL_SERVER,
1012         &IID_IShellWindows, (void**)&shellwindows);
1013     ok(hr == S_OK, "got 0x%08x\n", hr);
1014     /* TODO: remove when explorer startup with clean prefix is fixed */
1015     if (hr != S_OK)
1016         return;
1017 
1018 if (0) /* NULL out argument - currently crashes on Wine */ {
1019     hr = IShellWindows_Register(shellwindows, NULL, 0, SWC_EXPLORER, NULL);
1020     ok(hr == HRESULT_FROM_WIN32(RPC_X_NULL_REF_POINTER), "got 0x%08x\n", hr);
1021 }
1022     hr = IShellWindows_Register(shellwindows, NULL, 0, SWC_EXPLORER, &cookie);
1023 todo_wine
1024     ok(hr == E_POINTER, "got 0x%08x\n", hr);
1025 
1026     hr = IShellWindows_Register(shellwindows, (IDispatch*)shellwindows, 0, SWC_EXPLORER, &cookie);
1027 todo_wine
1028     ok(hr == E_POINTER, "got 0x%08x\n", hr);
1029 
1030     hr = IShellWindows_Register(shellwindows, (IDispatch*)shellwindows, 0, SWC_EXPLORER, &cookie);
1031 todo_wine
1032     ok(hr == E_POINTER, "got 0x%08x\n", hr);
1033 
1034     hwnd = CreateWindowExA(0, "button", "test", BS_CHECKBOX | WS_VISIBLE | WS_POPUP,
1035                            0, 0, 50, 14, 0, 0, 0, NULL);
1036     ok(hwnd != NULL, "got %p, error %d\n", hwnd, GetLastError());
1037 
1038     cookie = 0;
1039     hr = IShellWindows_Register(shellwindows, NULL, HandleToLong(hwnd), SWC_EXPLORER, &cookie);
1040 todo_wine {
1041     ok(hr == S_OK, "got 0x%08x\n", hr);
1042     ok(cookie != 0, "got %d\n", cookie);
1043 }
1044     cookie2 = 0;
1045     hr = IShellWindows_Register(shellwindows, NULL, HandleToLong(hwnd), SWC_EXPLORER, &cookie2);
1046 todo_wine {
1047     ok(hr == S_OK, "got 0x%08x\n", hr);
1048     ok(cookie2 != 0 && cookie2 != cookie, "got %d\n", cookie2);
1049 }
1050     hr = IShellWindows_Revoke(shellwindows, cookie);
1051 todo_wine
1052     ok(hr == S_OK, "got 0x%08x\n", hr);
1053     hr = IShellWindows_Revoke(shellwindows, cookie2);
1054 todo_wine
1055     ok(hr == S_OK, "got 0x%08x\n", hr);
1056 
1057     hr = IShellWindows_Revoke(shellwindows, 0);
1058 todo_wine
1059     ok(hr == S_FALSE, "got 0x%08x\n", hr);
1060 
1061     /* we can register ourselves as desktop, but FindWindowSW still returns real desktop window */
1062     cookie = 0;
1063     hr = IShellWindows_Register(shellwindows, NULL, HandleToLong(hwnd), SWC_DESKTOP, &cookie);
1064 todo_wine {
1065     ok(hr == S_OK, "got 0x%08x\n", hr);
1066     ok(cookie != 0, "got %d\n", cookie);
1067 }
1068     disp = (void*)0xdeadbeef;
1069     ret = 0xdead;
1070     VariantInit(&v);
1071     hr = IShellWindows_FindWindowSW(shellwindows, &v, &v, SWC_DESKTOP, &ret, SWFO_NEEDDISPATCH, &disp);
1072     ok(hr == S_OK || broken(hr == S_FALSE), "got 0x%08x\n", hr);
1073     if (hr == S_FALSE) /* winxp and earlier */ {
1074         win_skip("SWC_DESKTOP is not supported, some tests will be skipped.\n");
1075         /* older versions allowed to register SWC_DESKTOP and access it with FindWindowSW */
1076         ok(disp == NULL, "got %p\n", disp);
1077         ok(ret == 0, "got %d\n", ret);
1078     }
1079     else {
1080         static const IID *browser_riids[] = {
1081             &IID_IWebBrowser2,
1082             &IID_NULL
1083         };
1084 
1085         static const IID *viewdual_riids[] = {
1086             &IID_IShellFolderViewDual3,
1087             &IID_NULL
1088         };
1089 
1090         IShellFolderViewDual *view;
1091         IShellBrowser *sb, *sb2;
1092         IServiceProvider *sp;
1093         IDispatch *doc, *app;
1094         IWebBrowser2 *wb;
1095         IShellView *sv;
1096         IUnknown *unk;
1097 
1098         ok(disp != NULL, "got %p\n", disp);
1099 
1100         if (disp == NULL) goto skip_disp_tests;
1101 
1102         ok(ret != HandleToUlong(hwnd), "got %d\n", ret);
1103 
1104         /* IDispatch-related tests */
1105         test_dispatch_typeinfo(disp, browser_riids);
1106 
1107         /* IWebBrowser2 */
1108         hr = IDispatch_QueryInterface(disp, &IID_IWebBrowser2, (void**)&wb);
1109         ok(hr == S_OK, "got 0x%08x\n", hr);
1110 
1111         hr = IWebBrowser2_Refresh(wb);
1112 todo_wine
1113         ok(hr == S_OK, "got 0x%08x\n", hr);
1114 
1115         hr = IWebBrowser2_get_Application(wb, &app);
1116         ok(hr == S_OK, "got 0x%08x\n", hr);
1117         ok(disp == app, "got %p, %p\n", app, disp);
1118         IDispatch_Release(app);
1119 
1120         hr = IWebBrowser2_get_Document(wb, &doc);
1121 todo_wine
1122         ok(hr == S_OK, "got 0x%08x\n", hr);
1123 if (hr == S_OK) {
1124         test_dispatch_typeinfo(doc, viewdual_riids);
1125 }
1126         IWebBrowser2_Release(wb);
1127 
1128         /* IServiceProvider */
1129         hr = IDispatch_QueryInterface(disp, &IID_IShellFolderViewDual, (void**)&view);
1130         ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
1131 
1132         hr = IDispatch_QueryInterface(disp, &IID_IServiceProvider, (void**)&sp);
1133         ok(hr == S_OK, "got 0x%08x\n", hr);
1134 
1135         hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IShellBrowser, (void**)&sb);
1136         ok(hr == S_OK, "got 0x%08x\n", hr);
1137 
1138         hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IShellBrowser, (void**)&sb2);
1139         ok(hr == S_OK, "got 0x%08x\n", hr);
1140         ok(sb == sb2, "got %p, %p\n", sb, sb2);
1141 
1142         hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IOleWindow, (void**)&unk);
1143         ok(hr == S_OK, "got 0x%08x\n", hr);
1144         IUnknown_Release(unk);
1145 
1146         hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IExplorerBrowser, (void**)&unk);
1147         ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
1148 
1149         hr = IShellBrowser_QueryInterface(sb, &IID_IExplorerBrowser, (void**)&unk);
1150         ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
1151 
1152         hr = IShellBrowser_QueryInterface(sb, &IID_IWebBrowser2, (void**)&unk);
1153         ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
1154 
1155         hr = IShellBrowser_QueryInterface(sb, &IID_IDispatch, (void**)&unk);
1156         ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
1157 
1158         hr = IShellBrowser_QueryActiveShellView(sb, &sv);
1159         ok(hr == S_OK, "got 0x%08x\n", hr);
1160         IShellView_Release(sv);
1161 
1162         IShellBrowser_Release(sb2);
1163         IShellBrowser_Release(sb);
1164 
1165         hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IUnknown, (void**)&unk);
1166         ok(hr == S_OK, "got 0x%08x\n", hr);
1167 
1168         hr = IUnknown_QueryInterface(unk, &IID_IShellBrowser, (void**)&sb2);
1169         ok(hr == S_OK, "got 0x%08x\n", hr);
1170         IShellBrowser_Release(sb2);
1171         IUnknown_Release(unk);
1172 
1173         hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IShellView, (void**)&sv);
1174         ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
1175 
1176         IServiceProvider_Release(sp);
1177         IDispatch_Release(disp);
1178     }
1179 skip_disp_tests:
1180 
1181     disp = (void*)0xdeadbeef;
1182     ret = 0xdead;
1183     VariantInit(&v);
1184     hr = IShellWindows_FindWindowSW(shellwindows, &v, &v, SWC_DESKTOP, &ret, 0, &disp);
1185     ok(hr == S_OK || broken(hr == S_FALSE) /* winxp */, "got 0x%08x\n", hr);
1186     ok(disp == NULL, "got %p\n", disp);
1187     ok(ret != HandleToUlong(hwnd), "got %d\n", ret);
1188 
1189     disp = (void*)0xdeadbeef;
1190     ret = 0xdead;
1191     V_VT(&v) = VT_I4;
1192     V_I4(&v) = cookie;
1193     VariantInit(&v2);
1194     hr = IShellWindows_FindWindowSW(shellwindows, &v, &v2, SWC_BROWSER, &ret, SWFO_COOKIEPASSED, &disp);
1195 todo_wine
1196     ok(hr == S_FALSE, "got 0x%08x\n", hr);
1197     ok(disp == NULL, "got %p\n", disp);
1198     ok(ret == 0, "got %d\n", ret);
1199 
1200     hr = IShellWindows_Revoke(shellwindows, cookie);
1201 todo_wine
1202     ok(hr == S_OK, "got 0x%08x\n", hr);
1203     DestroyWindow(hwnd);
1204     IShellWindows_Release(shellwindows);
1205 }
1206 
1207 static void test_ParseName(void)
1208 {
1209     static const WCHAR cadabraW[] = {'c','a','d','a','b','r','a',0};
1210     WCHAR pathW[MAX_PATH];
1211     IShellDispatch *sd;
1212     FolderItem *item;
1213     Folder *folder;
1214     HRESULT hr;
1215     VARIANT v;
1216     BSTR str;
1217 
1218     hr = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER,
1219         &IID_IShellDispatch, (void**)&sd);
1220     ok(hr == S_OK, "got 0x%08x\n", hr);
1221 
1222     GetTempPathW(sizeof(pathW)/sizeof(pathW[0]), pathW);
1223     V_VT(&v) = VT_BSTR;
1224     V_BSTR(&v) = SysAllocString(pathW);
1225     hr = IShellDispatch_NameSpace(sd, v, &folder);
1226     ok(hr == S_OK, "got 0x%08x\n", hr);
1227     VariantClear(&v);
1228 
1229     item = (void*)0xdeadbeef;
1230     hr = Folder_ParseName(folder, NULL, &item);
1231     ok(hr == S_FALSE || broken(hr == E_INVALIDARG) /* win2k */, "got 0x%08x\n", hr);
1232     ok(item == NULL, "got %p\n", item);
1233 
1234     /* empty name */
1235     str = SysAllocStringLen(NULL, 0);
1236     item = (void*)0xdeadbeef;
1237     hr = Folder_ParseName(folder, str, &item);
1238     ok(hr == S_FALSE || broken(hr == E_INVALIDARG) /* win2k */, "got 0x%08x\n", hr);
1239     ok(item == NULL, "got %p\n", item);
1240     SysFreeString(str);
1241 
1242     /* path doesn't exist */
1243     str = SysAllocString(cadabraW);
1244     item = (void*)0xdeadbeef;
1245     hr = Folder_ParseName(folder, str, &item);
1246     ok(hr == S_FALSE || broken(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) /* win2k */,
1247         "got 0x%08x\n", hr);
1248     ok(item == NULL, "got %p\n", item);
1249     SysFreeString(str);
1250 
1251     lstrcatW(pathW, cadabraW);
1252     CreateDirectoryW(pathW, NULL);
1253 
1254     str = SysAllocString(cadabraW);
1255     item = NULL;
1256     hr = Folder_ParseName(folder, str, &item);
1257     ok(hr == S_OK, "got 0x%08x\n", hr);
1258     ok(item != NULL, "got %p\n", item);
1259     SysFreeString(str);
1260 
1261     hr = FolderItem_get_Path(item, &str);
1262     ok(hr == S_OK, "got 0x%08x\n", hr);
1263     ok(str[0] != 0, "path %s\n", wine_dbgstr_w(str));
1264     SysFreeString(str);
1265 
1266     RemoveDirectoryW(pathW);
1267     FolderItem_Release(item);
1268     Folder_Release(folder);
1269     IShellDispatch_Release(sd);
1270 }
1271 
1272 static void test_Verbs(void)
1273 {
1274     FolderItemVerbs *verbs, *verbs2;
1275     WCHAR pathW[MAX_PATH];
1276     FolderItemVerb *verb;
1277     IShellDispatch *sd;
1278     FolderItem *item;
1279     Folder2 *folder2;
1280     IDispatch *disp;
1281     Folder *folder;
1282     HRESULT hr;
1283     LONG count, i;
1284     VARIANT v;
1285     BSTR str;
1286 
1287     hr = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER,
1288         &IID_IShellDispatch, (void**)&sd);
1289     ok(hr == S_OK, "got 0x%08x\n", hr);
1290 
1291     GetTempPathW(sizeof(pathW)/sizeof(pathW[0]), pathW);
1292     V_VT(&v) = VT_BSTR;
1293     V_BSTR(&v) = SysAllocString(pathW);
1294     hr = IShellDispatch_NameSpace(sd, v, &folder);
1295     ok(hr == S_OK, "got 0x%08x\n", hr);
1296     VariantClear(&v);
1297 
1298     hr = Folder_QueryInterface(folder, &IID_Folder2, (void**)&folder2);
1299     ok(hr == S_OK, "got 0x%08x\n", hr);
1300     Folder_Release(folder);
1301 
1302     hr = Folder2_get_Self(folder2, &item);
1303     ok(hr == S_OK, "got 0x%08x\n", hr);
1304     Folder2_Release(folder2);
1305 
1306 if (0) { /* crashes on some systems */
1307     hr = FolderItem_Verbs(item, NULL);
1308     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1309 }
1310     hr = FolderItem_Verbs(item, &verbs);
1311     ok(hr == S_OK, "got 0x%08x\n", hr);
1312 
1313     hr = FolderItem_Verbs(item, &verbs2);
1314     ok(hr == S_OK, "got 0x%08x\n", hr);
1315     ok(verbs2 != verbs, "Unexpected verbs pointer.\n");
1316     FolderItemVerbs_Release(verbs2);
1317 
1318     disp = (void *)0xdeadbeef;
1319     hr = FolderItemVerbs_get_Application(verbs, &disp);
1320     ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
1321     ok(disp == NULL, "Unexpected application pointer.\n");
1322 
1323     disp = (void *)0xdeadbeef;
1324     hr = FolderItemVerbs_get_Parent(verbs, &disp);
1325     ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
1326     ok(disp == NULL, "Unexpected parent pointer %p.\n", disp);
1327 
1328 if (0) { /* crashes on winxp/win2k3 */
1329     hr = FolderItemVerbs_get_Count(verbs, NULL);
1330     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1331 }
1332     count = 0;
1333     hr = FolderItemVerbs_get_Count(verbs, &count);
1334     ok(hr == S_OK, "got 0x%08x\n", hr);
1335     ok(count > 0, "got count %d\n", count);
1336 
1337 if (0) { /* crashes on winxp/win2k3 */
1338     V_VT(&v) = VT_I4;
1339     V_I4(&v) = 0;
1340     hr = FolderItemVerbs_Item(verbs, v, NULL);
1341     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1342 }
1343     /* there's always one item more, so you can access [0,count],
1344        instead of actual [0,count) */
1345     for (i = 0; i <= count; i++) {
1346         V_VT(&v) = VT_I4;
1347         V_I4(&v) = i;
1348         hr = FolderItemVerbs_Item(verbs, v, &verb);
1349         ok(hr == S_OK, "got 0x%08x\n", hr);
1350         hr = FolderItemVerb_get_Name(verb, &str);
1351         ok(hr == S_OK, "got 0x%08x\n", hr);
1352         ok(str != NULL, "%d: name %s\n", i, wine_dbgstr_w(str));
1353         if (i == count)
1354             ok(str[0] == 0, "%d: got terminating item %s\n", i, wine_dbgstr_w(str));
1355 
1356         disp = (void *)0xdeadbeef;
1357         hr = FolderItemVerb_get_Parent(verb, &disp);
1358         ok(hr == E_NOTIMPL, "got %#x.\n", hr);
1359         ok(disp == NULL, "Unexpected parent pointer %p.\n", disp);
1360 
1361         disp = (void *)0xdeadbeef;
1362         hr = FolderItemVerb_get_Application(verb, &disp);
1363         ok(hr == E_NOTIMPL, "got %#x.\n", hr);
1364         ok(disp == NULL, "Unexpected parent pointer %p.\n", disp);
1365 
1366         SysFreeString(str);
1367         FolderItemVerb_Release(verb);
1368     }
1369 
1370     V_VT(&v) = VT_I4;
1371     V_I4(&v) = count+1;
1372     verb = NULL;
1373     hr = FolderItemVerbs_Item(verbs, v, &verb);
1374     ok(hr == S_OK, "got 0x%08x\n", hr);
1375     ok(verb == NULL, "got %p\n", verb);
1376 
1377     FolderItemVerbs_Release(verbs);
1378     FolderItem_Release(item);
1379     IShellDispatch_Release(sd);
1380 }
1381 
1382 static void test_ShellExecute(void)
1383 {
1384     HRESULT hr;
1385     IShellDispatch2 *sd;
1386     BSTR name;
1387     VARIANT args, dir, op, show;
1388 
1389     static const WCHAR regW[] = {'r','e','g',0};
1390 
1391     hr = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER,
1392         &IID_IShellDispatch2, (void**)&sd);
1393     if (hr != S_OK)
1394     {
1395         win_skip("IShellDispatch2 not supported\n");
1396         return;
1397     }
1398 
1399     VariantInit(&args);
1400     VariantInit(&dir);
1401     VariantInit(&op);
1402     VariantInit(&show);
1403 
1404     V_VT(&show) = VT_I4;
1405     V_I4(&show) = 0;
1406 
1407     name = SysAllocString(regW);
1408 
1409     hr = IShellDispatch2_ShellExecute(sd, name, args, dir, op, show);
1410     ok(hr == S_OK, "ShellExecute failed: %08x\n", hr);
1411 
1412     /* test invalid value for show */
1413     V_VT(&show) = VT_BSTR;
1414     V_BSTR(&show) = name;
1415 
1416     hr = IShellDispatch2_ShellExecute(sd, name, args, dir, op, show);
1417     ok(hr == S_OK, "ShellExecute failed: %08x\n", hr);
1418 
1419     SysFreeString(name);
1420     IShellDispatch2_Release(sd);
1421 }
1422 
1423 START_TEST(shelldispatch)
1424 {
1425     HRESULT r;
1426 
1427     r = CoInitialize(NULL);
1428     ok(SUCCEEDED(r), "CoInitialize failed: %08x\n", r);
1429     if (FAILED(r))
1430         return;
1431 
1432     init_function_pointers();
1433     test_namespace();
1434     test_items();
1435     test_service();
1436     test_ShellFolderViewDual();
1437     test_ShellWindows();
1438     test_ParseName();
1439     test_Verbs();
1440     test_ShellExecute();
1441 
1442     CoUninitialize();
1443 }
1444