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__)
_expect_ref(IUnknown * obj,ULONG ref,int 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
a2bstr(const char * str)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
variant_set_string(VARIANT * v,const char * s)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
init_function_pointers(void)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
test_namespace(void)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 < ARRAY_SIZE(special_folders); 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
test_items(void)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, 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;
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 < ARRAY_SIZE(file_defs); 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 == ARRAY_SIZE(file_defs), "got %d files\n", count);
545
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");
552
553 /* VT_I2 */
554 V_VT(&var) = VT_I2;
555 V_I2(&var) = 0;
556
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);
565
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);
573
574 FolderItem_Release(item);
575
576 /* VT_VARIANT | VT_BYREF */
577 V_VT(&var2) = VT_I2;
578 V_I2(&var2) = 0;
579
580 V_VT(&var) = VT_BYREF | VT_VARIANT;
581 V_VARIANTREF(&var) = &var2;
582
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);
588
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);
597
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");
603
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)
611 {
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);
619 }
620
621 V_VT(&int_index) = VT_I4;
622
623 /* test the folder item corresponding to each file */
624 for (i = 0; i < ARRAY_SIZE(file_defs); i++)
625 {
626 VARIANT_BOOL b;
627 BSTR name;
628
629 V_I4(&int_index) = i;
630 variant_set_string(&str_index, file_defs[i].name);
631
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);
636
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);
642
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);
650
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);
659
660 FolderItem_Release(item);
661
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);
666
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);
674
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);
679
680 FolderItem_Release(item);
681
682 if (file_defs[i].type == DIRECTORY)
683 {
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);
693
694 /* delete the file in the subdirectory */
695 ret = DeleteFileA(cstr);
696 ok(ret, "file_defs[%d]: DeleteFile failed: %08x\n", i, GetLastError());
697
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);
708 }
709 if (item2) FolderItem_Release(item2);
710 VariantClear(&str_index2);
711
712 /* remove the directory */
713 ret = RemoveDirectoryA(file_defs[i].name);
714 ok(ret, "file_defs[%d]: RemoveDirectory failed: %08x\n", i, GetLastError());
715 }
716 else
717 {
718 ret = DeleteFileA(file_defs[i].name);
719 ok(ret, "file_defs[%d]: DeleteFile failed: %08x\n", i, GetLastError());
720 }
721
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);
727
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);
735
736 FolderItem_Release(item);
737
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);
743
744 VariantClear(&str_index);
745 }
746
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");
753
754 if (0) /* crashes on xp */
755 {
756 r = FolderItems_get_Application(items, NULL);
757 ok(r == E_INVALIDARG, "expected E_INVALIDARG, got %08x\n", r);
758 }
759
760 r = FolderItems_get_Application(items, &disp);
761 ok(r == S_OK, "FolderItems::get_Application failed: %08x\n", r);
762
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);
768
769 if (0) /* crashes on xp */
770 {
771 r = FolderItems_get_Parent(items, NULL);
772 ok(r == E_NOTIMPL, "expected E_NOTIMPL, got %08x\n", r);
773 }
774
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");
779
780 if (0) /* crashes on xp */
781 {
782 r = FolderItems__NewEnum(items, NULL);
783 ok(r == E_INVALIDARG, "expected E_INVALIDARG, got %08x\n", r);
784 }
785
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);
792
793 if (items3)
794 {
795 r = FolderItems3_Filter(items3, 0, NULL);
796 todo_wine
797 ok(r == S_OK, "expected S_OK, got %08x\n", r);
798
799 if (0) /* crashes on xp */
800 {
801 r = FolderItems3_get_Verbs(items3, NULL);
802 ok(r == E_INVALIDARG, "expected E_INVALIDARG, got %08x\n", r);
803 }
804
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");
809 }
810
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);
817
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);
823
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");
830
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);
837
838 FolderItems_Release(items);
839 Folder_Release(folder);
840 if (items3) FolderItems3_Release(items3);
841 IShellDispatch_Release(sd);
842 }
843
test_service(void)844 static void test_service(void)
845 {
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;
855
856 hr = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER,
857 &IID_IShellDispatch2, (void**)&sd);
858 if (hr != S_OK)
859 {
860 win_skip("IShellDispatch2 not supported\n");
861 return;
862 }
863
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);
870
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);
876
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);
888
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);
897
898 IShellDispatch2_Release(sd);
899 }
900
test_dispatch_typeinfo(IDispatch * disp,REFIID * riid)901 static void test_dispatch_typeinfo(IDispatch *disp, REFIID *riid)
902 {
903 ITypeInfo *typeinfo;
904 TYPEATTR *typeattr;
905 UINT count;
906 HRESULT hr;
907
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);
912
913 hr = IDispatch_GetTypeInfo(disp, 0, LOCALE_SYSTEM_DEFAULT, &typeinfo);
914 ok(hr == S_OK, "got 0x%08x\n", hr);
915
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++;
922 }
923 ok(IsEqualGUID(&typeattr->guid, *riid), "unexpected type guid %s\n", wine_dbgstr_guid(&typeattr->guid));
924
925 ITypeInfo_ReleaseTypeAttr(typeinfo, typeattr);
926 ITypeInfo_Release(typeinfo);
927 }
928
test_ShellFolderViewDual(void)929 static void test_ShellFolderViewDual(void)
930 {
931 static const IID *shelldisp_riids[] = {
932 &IID_IShellDispatch6,
933 &IID_IShellDispatch5,
934 &IID_IShellDispatch4,
935 &IID_IShellDispatch2,
936 &IID_IWin7ShellDispatch6,
937 &IID_NULL
938 };
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;
946
947 /* IShellFolderViewDual is not an IShellView extension */
948 hr = SHGetDesktopFolder(&desktop);
949 ok(hr == S_OK, "got 0x%08x\n", hr);
950
951 hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
952 ok(hr == S_OK, "got 0x%08x\n", hr);
953
954 hr = IShellView_QueryInterface(view, &IID_IShellFolderViewDual, (void**)&viewdual);
955 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
956
957 hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IDispatch, (void**)&disp);
958 ok(hr == S_OK, "got 0x%08x\n", hr);
959
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);
964
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);
968
969 hr = IShellFolderViewDual_QueryInterface(viewdual, &IID_IShellView, (void**)&view2);
970 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
971
972 /* get_Application() */
973
974 if (0) /* crashes on pre-vista */ {
975 hr = IShellFolderViewDual_get_Application(viewdual, NULL);
976 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
977 }
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);
983
984 IShellFolderViewDual_Release(viewdual);
985 IDispatch_Release(disp);
986
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);
992
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);
997
998 hr = IShellFolder_BindToObject(desktop, pidl, NULL, &IID_IShellFolder, (void**)&tmpdir);
999 ok(hr == S_OK, "got 0x%08x\n", hr);
1000 CoTaskMemFree(pidl);
1001
1002 hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
1003 ok(hr == S_OK, "got 0x%08x\n", hr);
1004
1005 hr = IShellView_QueryInterface(view, &IID_IShellFolderViewDual, (void**)&viewdual);
1006 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
1007
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);
1012
1013 IShellFolder_Release(tmpdir);
1014 IShellFolder_Release(desktop);
1015 }
1016
test_ShellWindows(void)1017 static void test_ShellWindows(void)
1018 {
1019 IShellWindows *shellwindows;
1020 LONG cookie, cookie2, ret;
1021 IDispatch *disp;
1022 VARIANT v, v2;
1023 HRESULT hr;
1024 HWND hwnd;
1025
1026 hr = CoCreateInstance(&CLSID_ShellWindows, NULL, CLSCTX_LOCAL_SERVER,
1027 &IID_IShellWindows, (void**)&shellwindows);
1028 ok(hr == S_OK, "got 0x%08x\n", hr);
1029 /* TODO: remove when explorer startup with clean prefix is fixed */
1030 if (hr != S_OK)
1031 return;
1032
1033 hr = IShellWindows_Register(shellwindows, NULL, 0, SWC_EXPLORER, NULL);
1034 ok(hr == HRESULT_FROM_WIN32(RPC_X_NULL_REF_POINTER), "got 0x%08x\n", hr);
1035
1036 hr = IShellWindows_Register(shellwindows, NULL, 0, SWC_EXPLORER, &cookie);
1037 todo_wine
1038 ok(hr == E_POINTER, "got 0x%08x\n", hr);
1039
1040 hr = IShellWindows_Register(shellwindows, (IDispatch*)shellwindows, 0, SWC_EXPLORER, &cookie);
1041 todo_wine
1042 ok(hr == E_POINTER, "got 0x%08x\n", hr);
1043
1044 hr = IShellWindows_Register(shellwindows, (IDispatch*)shellwindows, 0, SWC_EXPLORER, &cookie);
1045 todo_wine
1046 ok(hr == E_POINTER, "got 0x%08x\n", hr);
1047
1048 hwnd = CreateWindowExA(0, "button", "test", BS_CHECKBOX | WS_VISIBLE | WS_POPUP,
1049 0, 0, 50, 14, 0, 0, 0, NULL);
1050 ok(hwnd != NULL, "got %p, error %d\n", hwnd, GetLastError());
1051
1052 cookie = 0;
1053 hr = IShellWindows_Register(shellwindows, NULL, HandleToLong(hwnd), SWC_EXPLORER, &cookie);
1054 todo_wine {
1055 ok(hr == S_OK, "got 0x%08x\n", hr);
1056 ok(cookie != 0, "got %d\n", cookie);
1057 }
1058 cookie2 = 0;
1059 hr = IShellWindows_Register(shellwindows, NULL, HandleToLong(hwnd), SWC_EXPLORER, &cookie2);
1060 todo_wine {
1061 ok(hr == S_OK, "got 0x%08x\n", hr);
1062 ok(cookie2 != 0 && cookie2 != cookie, "got %d\n", cookie2);
1063 }
1064 hr = IShellWindows_Revoke(shellwindows, cookie);
1065 todo_wine
1066 ok(hr == S_OK, "got 0x%08x\n", hr);
1067 hr = IShellWindows_Revoke(shellwindows, cookie2);
1068 todo_wine
1069 ok(hr == S_OK, "got 0x%08x\n", hr);
1070
1071 hr = IShellWindows_Revoke(shellwindows, 0);
1072 todo_wine
1073 ok(hr == S_FALSE, "got 0x%08x\n", hr);
1074
1075 /* we can register ourselves as desktop, but FindWindowSW still returns real desktop window */
1076 cookie = 0;
1077 hr = IShellWindows_Register(shellwindows, NULL, HandleToLong(hwnd), SWC_DESKTOP, &cookie);
1078 todo_wine {
1079 ok(hr == S_OK, "got 0x%08x\n", hr);
1080 ok(cookie != 0, "got %d\n", cookie);
1081 }
1082 disp = (void*)0xdeadbeef;
1083 ret = 0xdead;
1084 VariantInit(&v);
1085 hr = IShellWindows_FindWindowSW(shellwindows, &v, &v, SWC_DESKTOP, &ret, SWFO_NEEDDISPATCH, &disp);
1086 ok(hr == S_OK || broken(hr == S_FALSE), "got 0x%08x\n", hr);
1087 if (hr == S_FALSE) /* winxp and earlier */ {
1088 win_skip("SWC_DESKTOP is not supported, some tests will be skipped.\n");
1089 /* older versions allowed to register SWC_DESKTOP and access it with FindWindowSW */
1090 ok(disp == NULL, "got %p\n", disp);
1091 ok(ret == 0, "got %d\n", ret);
1092 }
1093 else {
1094 static const IID *browser_riids[] = {
1095 &IID_IWebBrowser2,
1096 &IID_NULL
1097 };
1098
1099 static const IID *viewdual_riids[] = {
1100 &IID_IShellFolderViewDual3,
1101 &IID_NULL
1102 };
1103
1104 IShellFolderViewDual *view;
1105 IShellBrowser *sb, *sb2;
1106 IServiceProvider *sp;
1107 IDispatch *doc, *app;
1108 IWebBrowser2 *wb;
1109 IShellView *sv;
1110 IUnknown *unk;
1111
1112 ok(disp != NULL, "got %p\n", disp);
1113 ok(ret != HandleToUlong(hwnd), "got %d\n", ret);
1114
1115 /* IDispatch-related tests */
1116 test_dispatch_typeinfo(disp, browser_riids);
1117
1118 /* IWebBrowser2 */
1119 hr = IDispatch_QueryInterface(disp, &IID_IWebBrowser2, (void**)&wb);
1120 ok(hr == S_OK, "got 0x%08x\n", hr);
1121
1122 hr = IWebBrowser2_Refresh(wb);
1123 todo_wine
1124 ok(hr == S_OK, "got 0x%08x\n", hr);
1125
1126 hr = IWebBrowser2_get_Application(wb, &app);
1127 ok(hr == S_OK, "got 0x%08x\n", hr);
1128 ok(disp == app, "got %p, %p\n", app, disp);
1129 IDispatch_Release(app);
1130
1131 hr = IWebBrowser2_get_Document(wb, &doc);
1132 todo_wine
1133 ok(hr == S_OK, "got 0x%08x\n", hr);
1134 if (hr == S_OK) {
1135 test_dispatch_typeinfo(doc, viewdual_riids);
1136 }
1137 IWebBrowser2_Release(wb);
1138
1139 /* IServiceProvider */
1140 hr = IDispatch_QueryInterface(disp, &IID_IShellFolderViewDual, (void**)&view);
1141 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
1142
1143 hr = IDispatch_QueryInterface(disp, &IID_IServiceProvider, (void**)&sp);
1144 ok(hr == S_OK, "got 0x%08x\n", hr);
1145
1146 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IShellBrowser, (void**)&sb);
1147 ok(hr == S_OK, "got 0x%08x\n", hr);
1148
1149 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IShellBrowser, (void**)&sb2);
1150 ok(hr == S_OK, "got 0x%08x\n", hr);
1151 ok(sb == sb2, "got %p, %p\n", sb, sb2);
1152
1153 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IOleWindow, (void**)&unk);
1154 ok(hr == S_OK, "got 0x%08x\n", hr);
1155 IUnknown_Release(unk);
1156
1157 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IExplorerBrowser, (void**)&unk);
1158 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
1159
1160 hr = IShellBrowser_QueryInterface(sb, &IID_IExplorerBrowser, (void**)&unk);
1161 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
1162
1163 hr = IShellBrowser_QueryInterface(sb, &IID_IWebBrowser2, (void**)&unk);
1164 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
1165
1166 hr = IShellBrowser_QueryInterface(sb, &IID_IDispatch, (void**)&unk);
1167 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
1168
1169 hr = IShellBrowser_QueryActiveShellView(sb, &sv);
1170 ok(hr == S_OK, "got 0x%08x\n", hr);
1171 IShellView_Release(sv);
1172
1173 IShellBrowser_Release(sb2);
1174 IShellBrowser_Release(sb);
1175
1176 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IUnknown, (void**)&unk);
1177 ok(hr == S_OK, "got 0x%08x\n", hr);
1178
1179 hr = IUnknown_QueryInterface(unk, &IID_IShellBrowser, (void**)&sb2);
1180 ok(hr == S_OK, "got 0x%08x\n", hr);
1181 IShellBrowser_Release(sb2);
1182 IUnknown_Release(unk);
1183
1184 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IShellView, (void**)&sv);
1185 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
1186
1187 IServiceProvider_Release(sp);
1188 IDispatch_Release(disp);
1189 }
1190
1191 disp = (void*)0xdeadbeef;
1192 ret = 0xdead;
1193 VariantInit(&v);
1194 hr = IShellWindows_FindWindowSW(shellwindows, &v, &v, SWC_DESKTOP, &ret, 0, &disp);
1195 ok(hr == S_OK || broken(hr == S_FALSE) /* winxp */, "got 0x%08x\n", hr);
1196 ok(disp == NULL, "got %p\n", disp);
1197 ok(ret != HandleToUlong(hwnd), "got %d\n", ret);
1198
1199 disp = (void*)0xdeadbeef;
1200 ret = 0xdead;
1201 V_VT(&v) = VT_I4;
1202 V_I4(&v) = cookie;
1203 VariantInit(&v2);
1204 hr = IShellWindows_FindWindowSW(shellwindows, &v, &v2, SWC_BROWSER, &ret, SWFO_COOKIEPASSED, &disp);
1205 todo_wine
1206 ok(hr == S_FALSE, "got 0x%08x\n", hr);
1207 ok(disp == NULL, "got %p\n", disp);
1208 ok(ret == 0, "got %d\n", ret);
1209
1210 hr = IShellWindows_Revoke(shellwindows, cookie);
1211 todo_wine
1212 ok(hr == S_OK, "got 0x%08x\n", hr);
1213 DestroyWindow(hwnd);
1214 IShellWindows_Release(shellwindows);
1215 }
1216
test_ParseName(void)1217 static void test_ParseName(void)
1218 {
1219 static const WCHAR cadabraW[] = {'c','a','d','a','b','r','a',0};
1220 WCHAR pathW[MAX_PATH];
1221 IShellDispatch *sd;
1222 FolderItem *item;
1223 Folder *folder;
1224 HRESULT hr;
1225 VARIANT v;
1226 BSTR str;
1227
1228 hr = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER,
1229 &IID_IShellDispatch, (void**)&sd);
1230 ok(hr == S_OK, "got 0x%08x\n", hr);
1231
1232 GetTempPathW(ARRAY_SIZE(pathW), pathW);
1233 V_VT(&v) = VT_BSTR;
1234 V_BSTR(&v) = SysAllocString(pathW);
1235 hr = IShellDispatch_NameSpace(sd, v, &folder);
1236 ok(hr == S_OK, "got 0x%08x\n", hr);
1237 VariantClear(&v);
1238
1239 item = (void*)0xdeadbeef;
1240 hr = Folder_ParseName(folder, NULL, &item);
1241 ok(hr == S_FALSE || broken(hr == E_INVALIDARG) /* win2k */, "got 0x%08x\n", hr);
1242 ok(item == NULL, "got %p\n", item);
1243
1244 /* empty name */
1245 str = SysAllocStringLen(NULL, 0);
1246 item = (void*)0xdeadbeef;
1247 hr = Folder_ParseName(folder, str, &item);
1248 ok(hr == S_FALSE || broken(hr == E_INVALIDARG) /* win2k */, "got 0x%08x\n", hr);
1249 ok(item == NULL, "got %p\n", item);
1250 SysFreeString(str);
1251
1252 /* path doesn't exist */
1253 str = SysAllocString(cadabraW);
1254 item = (void*)0xdeadbeef;
1255 hr = Folder_ParseName(folder, str, &item);
1256 ok(hr == S_FALSE || broken(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) /* win2k */,
1257 "got 0x%08x\n", hr);
1258 ok(item == NULL, "got %p\n", item);
1259 SysFreeString(str);
1260
1261 lstrcatW(pathW, cadabraW);
1262 CreateDirectoryW(pathW, NULL);
1263
1264 str = SysAllocString(cadabraW);
1265 item = NULL;
1266 hr = Folder_ParseName(folder, str, &item);
1267 ok(hr == S_OK, "got 0x%08x\n", hr);
1268 ok(item != NULL, "got %p\n", item);
1269 SysFreeString(str);
1270
1271 hr = FolderItem_get_Path(item, &str);
1272 ok(hr == S_OK, "got 0x%08x\n", hr);
1273 ok(str[0] != 0, "path %s\n", wine_dbgstr_w(str));
1274 SysFreeString(str);
1275
1276 RemoveDirectoryW(pathW);
1277 FolderItem_Release(item);
1278 Folder_Release(folder);
1279 IShellDispatch_Release(sd);
1280 }
1281
test_Verbs(void)1282 static void test_Verbs(void)
1283 {
1284 FolderItemVerbs *verbs, *verbs2;
1285 WCHAR pathW[MAX_PATH];
1286 FolderItemVerb *verb;
1287 IShellDispatch *sd;
1288 FolderItem *item;
1289 Folder2 *folder2;
1290 IDispatch *disp;
1291 Folder *folder;
1292 HRESULT hr;
1293 LONG count, i;
1294 VARIANT v;
1295 BSTR str;
1296
1297 hr = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER,
1298 &IID_IShellDispatch, (void**)&sd);
1299 ok(hr == S_OK, "got 0x%08x\n", hr);
1300
1301 GetTempPathW(ARRAY_SIZE(pathW), pathW);
1302 V_VT(&v) = VT_BSTR;
1303 V_BSTR(&v) = SysAllocString(pathW);
1304 hr = IShellDispatch_NameSpace(sd, v, &folder);
1305 ok(hr == S_OK, "got 0x%08x\n", hr);
1306 VariantClear(&v);
1307
1308 hr = Folder_QueryInterface(folder, &IID_Folder2, (void**)&folder2);
1309 ok(hr == S_OK, "got 0x%08x\n", hr);
1310 Folder_Release(folder);
1311
1312 hr = Folder2_get_Self(folder2, &item);
1313 ok(hr == S_OK, "got 0x%08x\n", hr);
1314 Folder2_Release(folder2);
1315
1316 if (0) { /* crashes on some systems */
1317 hr = FolderItem_Verbs(item, NULL);
1318 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1319 }
1320 hr = FolderItem_Verbs(item, &verbs);
1321 ok(hr == S_OK, "got 0x%08x\n", hr);
1322
1323 hr = FolderItem_Verbs(item, &verbs2);
1324 ok(hr == S_OK, "got 0x%08x\n", hr);
1325 ok(verbs2 != verbs, "Unexpected verbs pointer.\n");
1326 FolderItemVerbs_Release(verbs2);
1327
1328 disp = (void *)0xdeadbeef;
1329 hr = FolderItemVerbs_get_Application(verbs, &disp);
1330 ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
1331 ok(disp == NULL, "Unexpected application pointer.\n");
1332
1333 disp = (void *)0xdeadbeef;
1334 hr = FolderItemVerbs_get_Parent(verbs, &disp);
1335 ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
1336 ok(disp == NULL, "Unexpected parent pointer %p.\n", disp);
1337
1338 if (0) { /* crashes on winxp/win2k3 */
1339 hr = FolderItemVerbs_get_Count(verbs, NULL);
1340 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1341 }
1342 count = 0;
1343 hr = FolderItemVerbs_get_Count(verbs, &count);
1344 ok(hr == S_OK, "got 0x%08x\n", hr);
1345 ok(count > 0, "got count %d\n", count);
1346
1347 if (0) { /* crashes on winxp/win2k3 */
1348 V_VT(&v) = VT_I4;
1349 V_I4(&v) = 0;
1350 hr = FolderItemVerbs_Item(verbs, v, NULL);
1351 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1352 }
1353 /* there's always one item more, so you can access [0,count],
1354 instead of actual [0,count) */
1355 for (i = 0; i <= count; i++) {
1356 V_VT(&v) = VT_I4;
1357 V_I4(&v) = i;
1358 hr = FolderItemVerbs_Item(verbs, v, &verb);
1359 ok(hr == S_OK, "got 0x%08x\n", hr);
1360 hr = FolderItemVerb_get_Name(verb, &str);
1361 ok(hr == S_OK, "got 0x%08x\n", hr);
1362 ok(str != NULL, "%d: name %s\n", i, wine_dbgstr_w(str));
1363 if (i == count)
1364 ok(str[0] == 0, "%d: got terminating item %s\n", i, wine_dbgstr_w(str));
1365
1366 disp = (void *)0xdeadbeef;
1367 hr = FolderItemVerb_get_Parent(verb, &disp);
1368 ok(hr == E_NOTIMPL, "got %#x.\n", hr);
1369 ok(disp == NULL, "Unexpected parent pointer %p.\n", disp);
1370
1371 disp = (void *)0xdeadbeef;
1372 hr = FolderItemVerb_get_Application(verb, &disp);
1373 ok(hr == E_NOTIMPL, "got %#x.\n", hr);
1374 ok(disp == NULL, "Unexpected parent pointer %p.\n", disp);
1375
1376 SysFreeString(str);
1377 FolderItemVerb_Release(verb);
1378 }
1379
1380 V_VT(&v) = VT_I4;
1381 V_I4(&v) = count+1;
1382 verb = NULL;
1383 hr = FolderItemVerbs_Item(verbs, v, &verb);
1384 ok(hr == S_OK, "got 0x%08x\n", hr);
1385 ok(verb == NULL, "got %p\n", verb);
1386
1387 FolderItemVerbs_Release(verbs);
1388 FolderItem_Release(item);
1389 IShellDispatch_Release(sd);
1390 }
1391
test_ShellExecute(void)1392 static void test_ShellExecute(void)
1393 {
1394 HRESULT hr;
1395 IShellDispatch2 *sd;
1396 BSTR name;
1397 VARIANT args, dir, op, show;
1398
1399 static const WCHAR regW[] = {'r','e','g',0};
1400
1401 hr = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER,
1402 &IID_IShellDispatch2, (void**)&sd);
1403 if (hr != S_OK)
1404 {
1405 win_skip("IShellDispatch2 not supported\n");
1406 return;
1407 }
1408
1409 VariantInit(&args);
1410 VariantInit(&dir);
1411 VariantInit(&op);
1412 VariantInit(&show);
1413
1414 V_VT(&show) = VT_I4;
1415 V_I4(&show) = 0;
1416
1417 name = SysAllocString(regW);
1418
1419 hr = IShellDispatch2_ShellExecute(sd, name, args, dir, op, show);
1420 ok(hr == S_OK, "ShellExecute failed: %08x\n", hr);
1421
1422 /* test invalid value for show */
1423 V_VT(&show) = VT_BSTR;
1424 V_BSTR(&show) = name;
1425
1426 hr = IShellDispatch2_ShellExecute(sd, name, args, dir, op, show);
1427 ok(hr == S_OK, "ShellExecute failed: %08x\n", hr);
1428
1429 SysFreeString(name);
1430 IShellDispatch2_Release(sd);
1431 }
1432
START_TEST(shelldispatch)1433 START_TEST(shelldispatch)
1434 {
1435 HRESULT r;
1436
1437 r = CoInitialize(NULL);
1438 ok(SUCCEEDED(r), "CoInitialize failed: %08x\n", r);
1439 if (FAILED(r))
1440 return;
1441
1442 init_function_pointers();
1443 test_namespace();
1444 test_items();
1445 test_service();
1446 test_ShellFolderViewDual();
1447 test_ShellWindows();
1448 test_ParseName();
1449 test_Verbs();
1450 test_ShellExecute();
1451
1452 CoUninitialize();
1453 }
1454