04f664c1cfa5ea64310767d48d62d28f8089e7da
[reactos.git] / modules / rostests / winetests / shell32 / shelldispatch.c
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 "wine/test.h"
29
30 #include "initguid.h"
31
32 #define EXPECT_HR(hr,hr_exp) \
33 ok(hr == hr_exp, "got 0x%08x, expected 0x%08x\n", hr, hr_exp)
34
35 static const WCHAR winetestW[] = {'w','i','n','e','t','e','s','t',0};
36
37 static HRESULT (WINAPI *pSHGetFolderPathW)(HWND, int, HANDLE, DWORD, LPWSTR);
38 static HRESULT (WINAPI *pSHGetNameFromIDList)(PCIDLIST_ABSOLUTE,SIGDN,PWSTR*);
39 static HRESULT (WINAPI *pSHGetSpecialFolderLocation)(HWND, int, LPITEMIDLIST *);
40 static DWORD (WINAPI *pGetLongPathNameW)(LPCWSTR, LPWSTR, DWORD);
41
42 /* Updated Windows 7 has a new IShellDispatch6 in its typelib */
43 DEFINE_GUID(IID_IWin7ShellDispatch6, 0x34936ba1, 0x67ad, 0x4c41, 0x99,0xb8, 0x8c,0x12,0xdf,0xf1,0xe9,0x74);
44
45 static void init_function_pointers(void)
46 {
47 HMODULE hshell32, hkernel32;
48
49 hshell32 = GetModuleHandleA("shell32.dll");
50 hkernel32 = GetModuleHandleA("kernel32.dll");
51 pSHGetFolderPathW = (void*)GetProcAddress(hshell32, "SHGetFolderPathW");
52 pSHGetNameFromIDList = (void*)GetProcAddress(hshell32, "SHGetNameFromIDList");
53 pSHGetSpecialFolderLocation = (void*)GetProcAddress(hshell32,
54 "SHGetSpecialFolderLocation");
55 pGetLongPathNameW = (void*)GetProcAddress(hkernel32, "GetLongPathNameW");
56 }
57
58 static void test_namespace(void)
59 {
60 static const ShellSpecialFolderConstants special_folders[] =
61 {
62 ssfDESKTOP,
63 ssfPROGRAMS,
64 ssfCONTROLS,
65 ssfPRINTERS,
66 ssfPERSONAL,
67 ssfFAVORITES,
68 ssfSTARTUP,
69 ssfRECENT,
70 ssfSENDTO,
71 ssfBITBUCKET,
72 ssfSTARTMENU,
73 ssfDESKTOPDIRECTORY,
74 ssfDRIVES,
75 ssfNETWORK,
76 ssfNETHOOD,
77 ssfFONTS,
78 ssfTEMPLATES,
79 ssfCOMMONSTARTMENU,
80 ssfCOMMONPROGRAMS,
81 ssfCOMMONSTARTUP,
82 ssfCOMMONDESKTOPDIR,
83 ssfAPPDATA,
84 ssfPRINTHOOD,
85 ssfLOCALAPPDATA,
86 ssfALTSTARTUP,
87 ssfCOMMONALTSTARTUP,
88 ssfCOMMONFAVORITES,
89 ssfINTERNETCACHE,
90 ssfCOOKIES,
91 ssfHISTORY,
92 ssfCOMMONAPPDATA,
93 ssfWINDOWS,
94 ssfSYSTEM,
95 ssfPROGRAMFILES,
96 ssfMYPICTURES,
97 ssfPROFILE,
98 ssfSYSTEMx86,
99 ssfPROGRAMFILESx86,
100 };
101
102 static const WCHAR backslashW[] = {'\\',0};
103 static const WCHAR clsidW[] = {
104 ':',':','{','6','4','5','F','F','0','4','0','-','5','0','8','1','-',
105 '1','0','1','B','-','9','F','0','8','-',
106 '0','0','A','A','0','0','2','F','9','5','4','E','}',0};
107
108 static WCHAR tempW[MAX_PATH], curW[MAX_PATH];
109 WCHAR *long_pathW = NULL;
110 HRESULT r;
111 IShellDispatch *sd;
112 Folder *folder;
113 Folder2 *folder2;
114 FolderItem *item;
115 VARIANT var;
116 BSTR title, item_path;
117 int len, i;
118
119 r = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER,
120 &IID_IShellDispatch, (LPVOID*)&sd);
121 if (r == REGDB_E_CLASSNOTREG) /* NT4 */
122 {
123 win_skip("skipping IShellDispatch tests\n");
124 return;
125 }
126 ok(SUCCEEDED(r), "CoCreateInstance failed: %08x\n", r);
127 if (FAILED(r))
128 return;
129
130 VariantInit(&var);
131 folder = (void*)0xdeadbeef;
132 r = IShellDispatch_NameSpace(sd, var, &folder);
133 ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r);
134 ok(folder == NULL, "expected NULL, got %p\n", folder);
135
136 /* test valid folder ids */
137 for (i = 0; i < sizeof(special_folders)/sizeof(special_folders[0]); i++)
138 {
139 V_VT(&var) = VT_I4;
140 V_I4(&var) = special_folders[i];
141 folder = (void*)0xdeadbeef;
142 r = IShellDispatch_NameSpace(sd, var, &folder);
143 if (special_folders[i] == ssfALTSTARTUP || special_folders[i] == ssfCOMMONALTSTARTUP)
144 ok(r == S_OK || broken(r == S_FALSE) /* winxp */, "Failed to get folder for index %#x, got %08x\n", special_folders[i], r);
145 else
146 ok(r == S_OK, "Failed to get folder for index %#x, got %08x\n", special_folders[i], r);
147 if (folder)
148 Folder_Release(folder);
149 }
150
151 V_VT(&var) = VT_I4;
152 V_I4(&var) = -1;
153 folder = (void*)0xdeadbeef;
154 r = IShellDispatch_NameSpace(sd, var, &folder);
155 todo_wine {
156 ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r);
157 ok(folder == NULL, "got %p\n", folder);
158 if (r == S_OK)
159 Folder_Release(folder);
160 }
161 V_VT(&var) = VT_I4;
162 V_I4(&var) = ssfPROGRAMFILES;
163 r = IShellDispatch_NameSpace(sd, var, &folder);
164 ok(r == S_OK ||
165 broken(r == S_FALSE), /* NT4 */
166 "IShellDispatch::NameSpace failed: %08x\n", r);
167 if (r == S_OK)
168 {
169 static WCHAR path[MAX_PATH];
170
171 if (pSHGetFolderPathW)
172 {
173 r = pSHGetFolderPathW(NULL, CSIDL_PROGRAM_FILES, NULL,
174 SHGFP_TYPE_CURRENT, path);
175 ok(r == S_OK, "SHGetFolderPath failed: %08x\n", r);
176 }
177 r = Folder_get_Title(folder, &title);
178 todo_wine
179 ok(r == S_OK, "Folder::get_Title failed: %08x\n", r);
180 if (r == S_OK)
181 {
182 /* On Win2000-2003 title is equal to program files directory name in
183 HKLM\Software\Microsoft\Windows\CurrentVersion\ProgramFilesDir.
184 On newer Windows it seems constant and is not changed
185 if the program files directory name is changed */
186 if (pSHGetSpecialFolderLocation && pSHGetNameFromIDList)
187 {
188 LPITEMIDLIST pidl;
189 PWSTR name;
190
191 r = pSHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidl);
192 ok(r == S_OK, "SHGetSpecialFolderLocation failed: %08x\n", r);
193 r = pSHGetNameFromIDList(pidl, SIGDN_NORMALDISPLAY, &name);
194 ok(r == S_OK, "SHGetNameFromIDList failed: %08x\n", r);
195 todo_wine
196 ok(!lstrcmpW(title, name), "expected %s, got %s\n",
197 wine_dbgstr_w(name), wine_dbgstr_w(title));
198 CoTaskMemFree(name);
199 CoTaskMemFree(pidl);
200 }
201 else if (pSHGetFolderPathW)
202 {
203 WCHAR *p;
204
205 p = path + lstrlenW(path);
206 while (path < p && *(p - 1) != '\\')
207 p--;
208 ok(!lstrcmpiW(title, p), "expected %s, got %s\n",
209 wine_dbgstr_w(p), wine_dbgstr_w(title));
210 }
211 else skip("skipping Folder::get_Title test\n");
212 SysFreeString(title);
213 }
214 r = Folder_QueryInterface(folder, &IID_Folder2, (LPVOID*)&folder2);
215 ok(r == S_OK, "Folder::QueryInterface failed: %08x\n", r);
216 if (r == S_OK)
217 {
218 r = Folder2_get_Self(folder2, &item);
219 ok(r == S_OK, "Folder::get_Self failed: %08x\n", r);
220 if (r == S_OK)
221 {
222 r = FolderItem_get_Path(item, &item_path);
223 ok(r == S_OK, "FolderItem::get_Path failed: %08x\n", r);
224 if (pSHGetFolderPathW)
225 ok(!lstrcmpiW(item_path, path), "expected %s, got %s\n",
226 wine_dbgstr_w(path), wine_dbgstr_w(item_path));
227 SysFreeString(item_path);
228 FolderItem_Release(item);
229 }
230 Folder2_Release(folder2);
231 }
232 Folder_Release(folder);
233 }
234
235 V_VT(&var) = VT_I4;
236 V_I4(&var) = ssfBITBUCKET;
237 r = IShellDispatch_NameSpace(sd, var, &folder);
238 ok(r == S_OK ||
239 broken(r == S_FALSE), /* NT4 */
240 "IShellDispatch::NameSpace failed: %08x\n", r);
241 if (r == S_OK)
242 {
243 r = Folder_QueryInterface(folder, &IID_Folder2, (LPVOID*)&folder2);
244 ok(r == S_OK ||
245 broken(r == E_NOINTERFACE), /* NT4 */
246 "Folder::QueryInterface failed: %08x\n", r);
247 if (r == S_OK)
248 {
249 r = Folder2_get_Self(folder2, &item);
250 ok(r == S_OK, "Folder::get_Self failed: %08x\n", r);
251 if (r == S_OK)
252 {
253 r = FolderItem_get_Path(item, &item_path);
254 todo_wine
255 ok(r == S_OK, "FolderItem::get_Path failed: %08x\n", r);
256 todo_wine
257 ok(!lstrcmpW(item_path, clsidW), "expected %s, got %s\n",
258 wine_dbgstr_w(clsidW), wine_dbgstr_w(item_path));
259 SysFreeString(item_path);
260 FolderItem_Release(item);
261 }
262 Folder2_Release(folder2);
263 }
264 Folder_Release(folder);
265 }
266
267 GetTempPathW(MAX_PATH, tempW);
268 GetCurrentDirectoryW(MAX_PATH, curW);
269 SetCurrentDirectoryW(tempW);
270 CreateDirectoryW(winetestW, NULL);
271 V_VT(&var) = VT_BSTR;
272 V_BSTR(&var) = SysAllocString(winetestW);
273 r = IShellDispatch_NameSpace(sd, var, &folder);
274 ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r);
275 SysFreeString(V_BSTR(&var));
276
277 GetFullPathNameW(winetestW, MAX_PATH, tempW, NULL);
278 if (pGetLongPathNameW)
279 {
280 len = pGetLongPathNameW(tempW, NULL, 0);
281 long_pathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
282 if (long_pathW)
283 pGetLongPathNameW(tempW, long_pathW, len);
284 }
285 V_VT(&var) = VT_BSTR;
286 V_BSTR(&var) = SysAllocString(tempW);
287 r = IShellDispatch_NameSpace(sd, var, &folder);
288 ok(r == S_OK, "IShellDispatch::NameSpace failed: %08x\n", r);
289 if (r == S_OK)
290 {
291 r = Folder_get_Title(folder, &title);
292 ok(r == S_OK, "Folder::get_Title failed: %08x\n", r);
293 if (r == S_OK)
294 {
295 ok(!lstrcmpW(title, winetestW), "bad title: %s\n",
296 wine_dbgstr_w(title));
297 SysFreeString(title);
298 }
299 r = Folder_QueryInterface(folder, &IID_Folder2, (LPVOID*)&folder2);
300 ok(r == S_OK ||
301 broken(r == E_NOINTERFACE), /* NT4 */
302 "Folder::QueryInterface failed: %08x\n", r);
303 if (r == S_OK)
304 {
305 r = Folder2_get_Self(folder2, &item);
306 ok(r == S_OK, "Folder::get_Self failed: %08x\n", r);
307 if (r == S_OK)
308 {
309 r = FolderItem_get_Path(item, &item_path);
310 ok(r == S_OK, "FolderItem::get_Path failed: %08x\n", r);
311 if (long_pathW)
312 ok(!lstrcmpW(item_path, long_pathW),
313 "expected %s, got %s\n", wine_dbgstr_w(long_pathW),
314 wine_dbgstr_w(item_path));
315 SysFreeString(item_path);
316 FolderItem_Release(item);
317 }
318 Folder2_Release(folder2);
319 }
320 Folder_Release(folder);
321 }
322 SysFreeString(V_BSTR(&var));
323
324 len = lstrlenW(tempW);
325 if (len < MAX_PATH - 1)
326 {
327 lstrcatW(tempW, backslashW);
328 V_VT(&var) = VT_BSTR;
329 V_BSTR(&var) = SysAllocString(tempW);
330 r = IShellDispatch_NameSpace(sd, var, &folder);
331 ok(r == S_OK, "IShellDispatch::NameSpace failed: %08x\n", r);
332 if (r == S_OK)
333 {
334 r = Folder_get_Title(folder, &title);
335 ok(r == S_OK, "Folder::get_Title failed: %08x\n", r);
336 if (r == S_OK)
337 {
338 ok(!lstrcmpW(title, winetestW), "bad title: %s\n",
339 wine_dbgstr_w(title));
340 SysFreeString(title);
341 }
342 r = Folder_QueryInterface(folder, &IID_Folder2, (LPVOID*)&folder2);
343 ok(r == S_OK ||
344 broken(r == E_NOINTERFACE), /* NT4 */
345 "Folder::QueryInterface failed: %08x\n", r);
346 if (r == S_OK)
347 {
348 r = Folder2_get_Self(folder2, &item);
349 ok(r == S_OK, "Folder::get_Self failed: %08x\n", r);
350 if (r == S_OK)
351 {
352 r = FolderItem_get_Path(item, &item_path);
353 ok(r == S_OK, "FolderItem::get_Path failed: %08x\n", r);
354 if (long_pathW)
355 ok(!lstrcmpW(item_path, long_pathW),
356 "expected %s, got %s\n", wine_dbgstr_w(long_pathW),
357 wine_dbgstr_w(item_path));
358 SysFreeString(item_path);
359 FolderItem_Release(item);
360 }
361 Folder2_Release(folder2);
362 }
363 Folder_Release(folder);
364 }
365 SysFreeString(V_BSTR(&var));
366 }
367
368 HeapFree(GetProcessHeap(), 0, long_pathW);
369 RemoveDirectoryW(winetestW);
370 SetCurrentDirectoryW(curW);
371 IShellDispatch_Release(sd);
372 }
373
374 static void test_items(void)
375 {
376 WCHAR wstr[MAX_PATH], orig_dir[MAX_PATH];
377 HRESULT r;
378 IShellDispatch *sd = NULL;
379 Folder *folder = NULL;
380 FolderItems *items = NULL;
381 FolderItems2 *items2 = NULL;
382 FolderItems3 *items3 = NULL;
383 FolderItem *item = (FolderItem*)0xdeadbeef;
384 IDispatch *disp = NULL;
385 IUnknown *unk = NULL;
386 FolderItemVerbs *verbs = (FolderItemVerbs*)0xdeadbeef;
387 VARIANT var;
388 LONG lcount = -1;
389
390 r = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, &IID_IShellDispatch, (void**)&sd);
391 ok(SUCCEEDED(r), "CoCreateInstance failed: %08x\n", r);
392 ok(!!sd, "sd is null\n");
393
394 GetTempPathW(MAX_PATH, wstr);
395 GetCurrentDirectoryW(MAX_PATH, orig_dir);
396 SetCurrentDirectoryW(wstr);
397 CreateDirectoryW(winetestW, NULL);
398 GetFullPathNameW(winetestW, MAX_PATH, wstr, NULL);
399 V_VT(&var) = VT_BSTR;
400 V_BSTR(&var) = SysAllocString(wstr);
401 r = IShellDispatch_NameSpace(sd, var, &folder);
402 ok(r == S_OK, "IShellDispatch::NameSpace failed: %08x\n", r);
403 ok(!!folder, "folder is null\n");
404 SysFreeString(V_BSTR(&var));
405 IShellDispatch_Release(sd);
406 SetCurrentDirectoryW(winetestW);
407
408 r = Folder_Items(folder, &items);
409 ok(r == S_OK, "Folder::Items failed: %08x\n", r);
410 ok(!!items, "items is null\n");
411 r = FolderItems_QueryInterface(items, &IID_FolderItems2, (void**)&items2);
412 ok(r == S_OK || broken(r == E_NOINTERFACE) /* xp and later */, "FolderItems::QueryInterface failed: %08x\n", r);
413 ok(!!items2 || broken(!items2) /* xp and later */, "items2 is null\n");
414 r = FolderItems_QueryInterface(items, &IID_FolderItems3, (void**)&items3);
415 ok(r == S_OK, "FolderItems::QueryInterface failed: %08x\n", r);
416 ok(!!items3, "items3 is null\n");
417 Folder_Release(folder);
418
419 if (0) /* crashes on all versions of Windows */
420 r = FolderItems_get_Count(items, NULL);
421
422 r = FolderItems_get_Count(items, &lcount);
423 ok(r == S_OK, "FolderItems::get_Count failed: %08x\n", r);
424 ok(!lcount, "expected 0 files, got %d\n", lcount);
425
426 V_VT(&var) = VT_I4;
427 V_I4(&var) = 0;
428
429 if (0) /* crashes on all versions of Windows */
430 r = FolderItems_Item(items, var, NULL);
431
432 r = FolderItems_Item(items, var, &item);
433 todo_wine
434 ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r);
435 ok(!item, "item is not null\n");
436
437 if (0) /* crashes on xp */
438 {
439 r = FolderItems_get_Application(items, NULL);
440 ok(r == E_INVALIDARG, "expected E_INVALIDARG, got %08x\n", r);
441 }
442
443 r = FolderItems_get_Application(items, &disp);
444 todo_wine
445 ok(r == S_OK, "FolderItems::get_Application failed: %08x\n", r);
446 todo_wine
447 ok(!!disp, "disp is null\n");
448 if (disp) IDispatch_Release(disp);
449
450 if (0) /* crashes on xp */
451 {
452 r = FolderItems_get_Parent(items, NULL);
453 ok(r == E_NOTIMPL, "expected E_NOTIMPL, got %08x\n", r);
454 }
455
456 disp = (IDispatch*)0xdeadbeef;
457 r = FolderItems_get_Parent(items, &disp);
458 ok(r == E_NOTIMPL, "expected E_NOTIMPL, got %08x\n", r);
459 ok(!disp, "disp is not null\n");
460
461 if (0) /* crashes on xp */
462 {
463 r = FolderItems__NewEnum(items, NULL);
464 ok(r == E_INVALIDARG, "expected E_INVALIDARG, got %08x\n", r);
465 }
466
467 r = FolderItems__NewEnum(items, &unk);
468 todo_wine
469 ok(r == S_OK, "FolderItems::_NewEnum failed: %08x\n", r);
470 todo_wine
471 ok(!!unk, "unk is null\n");
472 if (unk) IUnknown_Release(unk);
473
474 if (items3)
475 {
476 r = FolderItems3_Filter(items3, 0, NULL);
477 todo_wine
478 ok(r == S_OK, "expected S_OK, got %08x\n", r);
479
480 if (0) /* crashes on xp */
481 {
482 r = FolderItems3_get_Verbs(items3, NULL);
483 ok(r == E_INVALIDARG, "expected E_INVALIDARG, got %08x\n", r);
484 }
485
486 r = FolderItems3_get_Verbs(items3, &verbs);
487 todo_wine
488 ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r);
489 ok(!verbs, "verbs is not null\n");
490 }
491
492 GetTempPathW(MAX_PATH, wstr);
493 SetCurrentDirectoryW(wstr);
494 RemoveDirectoryW(winetestW);
495 SetCurrentDirectoryW(orig_dir);
496
497 FolderItems_Release(items);
498 if (items2) FolderItems2_Release(items2);
499 if (items3) FolderItems3_Release(items3);
500 }
501
502 static void test_service(void)
503 {
504 static const WCHAR spooler[] = {'S','p','o','o','l','e','r',0};
505 static const WCHAR dummyW[] = {'d','u','m','m','y',0};
506 SERVICE_STATUS_PROCESS status;
507 SC_HANDLE scm, service;
508 IShellDispatch2 *sd;
509 DWORD dummy;
510 HRESULT hr;
511 BSTR name;
512 VARIANT v;
513
514 hr = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER,
515 &IID_IShellDispatch2, (void**)&sd);
516 if (hr != S_OK)
517 {
518 win_skip("IShellDispatch2 not supported\n");
519 return;
520 }
521
522 V_VT(&v) = VT_I2;
523 V_I2(&v) = 10;
524 hr = IShellDispatch2_IsServiceRunning(sd, NULL, &v);
525 ok(V_VT(&v) == VT_BOOL, "got %d\n", V_VT(&v));
526 ok(V_BOOL(&v) == VARIANT_FALSE, "got %d\n", V_BOOL(&v));
527 EXPECT_HR(hr, S_OK);
528
529 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
530 service = OpenServiceW(scm, spooler, SERVICE_QUERY_STATUS);
531 QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy);
532 CloseServiceHandle(service);
533 CloseServiceHandle(scm);
534
535 /* service should exist */
536 name = SysAllocString(spooler);
537 V_VT(&v) = VT_I2;
538 hr = IShellDispatch2_IsServiceRunning(sd, name, &v);
539 EXPECT_HR(hr, S_OK);
540 ok(V_VT(&v) == VT_BOOL, "got %d\n", V_VT(&v));
541 if (status.dwCurrentState == SERVICE_RUNNING)
542 ok(V_BOOL(&v) == VARIANT_TRUE, "got %d\n", V_BOOL(&v));
543 else
544 ok(V_BOOL(&v) == VARIANT_FALSE, "got %d\n", V_BOOL(&v));
545 SysFreeString(name);
546
547 /* service doesn't exist */
548 name = SysAllocString(dummyW);
549 V_VT(&v) = VT_I2;
550 hr = IShellDispatch2_IsServiceRunning(sd, name, &v);
551 EXPECT_HR(hr, S_OK);
552 ok(V_VT(&v) == VT_BOOL, "got %d\n", V_VT(&v));
553 ok(V_BOOL(&v) == VARIANT_FALSE, "got %d\n", V_BOOL(&v));
554 SysFreeString(name);
555
556 IShellDispatch2_Release(sd);
557 }
558
559 static void test_dispatch_typeinfo(IDispatch *disp, REFIID *riid)
560 {
561 ITypeInfo *typeinfo;
562 TYPEATTR *typeattr;
563 UINT count;
564 HRESULT hr;
565
566 count = 10;
567 hr = IDispatch_GetTypeInfoCount(disp, &count);
568 ok(hr == S_OK, "got 0x%08x\n", hr);
569 ok(count == 1, "got %u\n", count);
570
571 hr = IDispatch_GetTypeInfo(disp, 0, LOCALE_SYSTEM_DEFAULT, &typeinfo);
572 ok(hr == S_OK, "got 0x%08x\n", hr);
573
574 hr = ITypeInfo_GetTypeAttr(typeinfo, &typeattr);
575 ok(hr == S_OK, "got 0x%08x\n", hr);
576 while (!IsEqualGUID(*riid, &IID_NULL)) {
577 if (IsEqualGUID(&typeattr->guid, *riid))
578 break;
579 riid++;
580 }
581 ok(IsEqualGUID(&typeattr->guid, *riid), "unexpected type guid %s\n", wine_dbgstr_guid(&typeattr->guid));
582
583 ITypeInfo_ReleaseTypeAttr(typeinfo, typeattr);
584 ITypeInfo_Release(typeinfo);
585 }
586
587 static void test_ShellFolderViewDual(void)
588 {
589 static const IID *shelldisp_riids[] = {
590 &IID_IShellDispatch6,
591 &IID_IShellDispatch5,
592 &IID_IShellDispatch4,
593 &IID_IShellDispatch2,
594 &IID_IWin7ShellDispatch6,
595 &IID_NULL
596 };
597 IShellFolderViewDual *viewdual;
598 IShellFolder *desktop, *tmpdir;
599 IShellView *view, *view2;
600 IDispatch *disp, *disp2;
601 WCHAR pathW[MAX_PATH];
602 LPITEMIDLIST pidl;
603 HRESULT hr;
604
605 /* IShellFolderViewDual is not an IShellView extension */
606 hr = SHGetDesktopFolder(&desktop);
607 ok(hr == S_OK, "got 0x%08x\n", hr);
608
609 hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
610 ok(hr == S_OK, "got 0x%08x\n", hr);
611
612 hr = IShellView_QueryInterface(view, &IID_IShellFolderViewDual, (void**)&viewdual);
613 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
614
615 hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IDispatch, (void**)&disp);
616 ok(hr == S_OK, "got 0x%08x\n", hr);
617
618 hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IDispatch, (void**)&disp2);
619 ok(hr == S_OK, "got 0x%08x\n", hr);
620 ok(disp2 == disp, "got %p, %p\n", disp2, disp);
621 IDispatch_Release(disp2);
622
623 hr = IDispatch_QueryInterface(disp, &IID_IShellFolderViewDual, (void**)&viewdual);
624 ok(hr == S_OK, "got 0x%08x\n", hr);
625 ok(disp == (IDispatch*)viewdual, "got %p, expected %p\n", viewdual, disp);
626
627 hr = IShellFolderViewDual_QueryInterface(viewdual, &IID_IShellView, (void**)&view2);
628 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
629
630 /* get_Application() */
631
632 if (0) /* crashes on pre-vista */ {
633 hr = IShellFolderViewDual_get_Application(viewdual, NULL);
634 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
635 }
636 hr = IShellFolderViewDual_get_Application(viewdual, &disp2);
637 ok(hr == S_OK, "got 0x%08x\n", hr);
638 ok(disp2 != (IDispatch*)viewdual, "got %p, %p\n", disp2, viewdual);
639 test_dispatch_typeinfo(disp2, shelldisp_riids);
640 IDispatch_Release(disp2);
641
642 IShellFolderViewDual_Release(viewdual);
643 IDispatch_Release(disp);
644
645 disp = (void*)0xdeadbeef;
646 hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IShellFolderViewDual, (void**)&disp);
647 ok(hr == E_NOINTERFACE || broken(hr == E_NOTIMPL) /* win2k */, "got 0x%08x\n", hr);
648 ok(disp == NULL, "got %p\n", disp);
649 IShellView_Release(view);
650
651 /* Try with some other folder, that's not a desktop */
652 GetTempPathW(sizeof(pathW)/sizeof(pathW[0]), pathW);
653 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, pathW, NULL, &pidl, NULL);
654 ok(hr == S_OK, "got 0x%08x\n", hr);
655
656 hr = IShellFolder_BindToObject(desktop, pidl, NULL, &IID_IShellFolder, (void**)&tmpdir);
657 ok(hr == S_OK, "got 0x%08x\n", hr);
658 CoTaskMemFree(pidl);
659
660 hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
661 ok(hr == S_OK, "got 0x%08x\n", hr);
662
663 hr = IShellView_QueryInterface(view, &IID_IShellFolderViewDual, (void**)&viewdual);
664 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
665
666 hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IDispatch, (void**)&disp);
667 ok(hr == S_OK, "got 0x%08x\n", hr);
668 IDispatch_Release(disp);
669 IShellView_Release(view);
670
671 IShellFolder_Release(tmpdir);
672 IShellFolder_Release(desktop);
673 }
674
675 static void test_ShellWindows(void)
676 {
677 IShellWindows *shellwindows;
678 LONG cookie, cookie2, ret;
679 IDispatch *disp;
680 VARIANT v, v2;
681 HRESULT hr;
682 HWND hwnd;
683
684 hr = CoCreateInstance(&CLSID_ShellWindows, NULL, CLSCTX_LOCAL_SERVER,
685 &IID_IShellWindows, (void**)&shellwindows);
686 ok(hr == S_OK, "got 0x%08x\n", hr);
687 /* TODO: remove when explorer startup with clean prefix is fixed */
688 if (hr != S_OK)
689 return;
690
691 if (0) /* NULL out argument - currently crashes on Wine */ {
692 hr = IShellWindows_Register(shellwindows, NULL, 0, SWC_EXPLORER, NULL);
693 ok(hr == HRESULT_FROM_WIN32(RPC_X_NULL_REF_POINTER), "got 0x%08x\n", hr);
694 }
695 hr = IShellWindows_Register(shellwindows, NULL, 0, SWC_EXPLORER, &cookie);
696 todo_wine
697 ok(hr == E_POINTER, "got 0x%08x\n", hr);
698
699 hr = IShellWindows_Register(shellwindows, (IDispatch*)shellwindows, 0, SWC_EXPLORER, &cookie);
700 todo_wine
701 ok(hr == E_POINTER, "got 0x%08x\n", hr);
702
703 hr = IShellWindows_Register(shellwindows, (IDispatch*)shellwindows, 0, SWC_EXPLORER, &cookie);
704 todo_wine
705 ok(hr == E_POINTER, "got 0x%08x\n", hr);
706
707 hwnd = CreateWindowExA(0, "button", "test", BS_CHECKBOX | WS_VISIBLE | WS_POPUP,
708 0, 0, 50, 14, 0, 0, 0, NULL);
709 ok(hwnd != NULL, "got %p, error %d\n", hwnd, GetLastError());
710
711 cookie = 0;
712 hr = IShellWindows_Register(shellwindows, NULL, HandleToLong(hwnd), SWC_EXPLORER, &cookie);
713 todo_wine {
714 ok(hr == S_OK, "got 0x%08x\n", hr);
715 ok(cookie != 0, "got %d\n", cookie);
716 }
717 cookie2 = 0;
718 hr = IShellWindows_Register(shellwindows, NULL, HandleToLong(hwnd), SWC_EXPLORER, &cookie2);
719 todo_wine {
720 ok(hr == S_OK, "got 0x%08x\n", hr);
721 ok(cookie2 != 0 && cookie2 != cookie, "got %d\n", cookie2);
722 }
723 hr = IShellWindows_Revoke(shellwindows, cookie);
724 todo_wine
725 ok(hr == S_OK, "got 0x%08x\n", hr);
726 hr = IShellWindows_Revoke(shellwindows, cookie2);
727 todo_wine
728 ok(hr == S_OK, "got 0x%08x\n", hr);
729
730 hr = IShellWindows_Revoke(shellwindows, 0);
731 todo_wine
732 ok(hr == S_FALSE, "got 0x%08x\n", hr);
733
734 /* we can register ourselves as desktop, but FindWindowSW still returns real desktop window */
735 cookie = 0;
736 hr = IShellWindows_Register(shellwindows, NULL, HandleToLong(hwnd), SWC_DESKTOP, &cookie);
737 todo_wine {
738 ok(hr == S_OK, "got 0x%08x\n", hr);
739 ok(cookie != 0, "got %d\n", cookie);
740 }
741 disp = (void*)0xdeadbeef;
742 ret = 0xdead;
743 VariantInit(&v);
744 hr = IShellWindows_FindWindowSW(shellwindows, &v, &v, SWC_DESKTOP, &ret, SWFO_NEEDDISPATCH, &disp);
745 ok(hr == S_OK || broken(hr == S_FALSE), "got 0x%08x\n", hr);
746 if (hr == S_FALSE) /* winxp and earlier */ {
747 win_skip("SWC_DESKTOP is not supported, some tests will be skipped.\n");
748 /* older versions allowed to regiser SWC_DESKTOP and access it with FindWindowSW */
749 ok(disp == NULL, "got %p\n", disp);
750 ok(ret == 0, "got %d\n", ret);
751 }
752 else {
753 static const IID *browser_riids[] = {
754 &IID_IWebBrowser2,
755 &IID_NULL
756 };
757
758 static const IID *viewdual_riids[] = {
759 &IID_IShellFolderViewDual3,
760 &IID_NULL
761 };
762
763 IShellFolderViewDual *view;
764 IShellBrowser *sb, *sb2;
765 IServiceProvider *sp;
766 IDispatch *doc, *app;
767 IWebBrowser2 *wb;
768 IShellView *sv;
769 IUnknown *unk;
770
771 ok(disp != NULL, "got %p\n", disp);
772 ok(ret != HandleToUlong(hwnd), "got %d\n", ret);
773
774 /* IDispatch-related tests */
775 test_dispatch_typeinfo(disp, browser_riids);
776
777 /* IWebBrowser2 */
778 hr = IDispatch_QueryInterface(disp, &IID_IWebBrowser2, (void**)&wb);
779 ok(hr == S_OK, "got 0x%08x\n", hr);
780
781 hr = IWebBrowser2_Refresh(wb);
782 todo_wine
783 ok(hr == S_OK, "got 0x%08x\n", hr);
784
785 hr = IWebBrowser2_get_Application(wb, &app);
786 ok(hr == S_OK, "got 0x%08x\n", hr);
787 ok(disp == app, "got %p, %p\n", app, disp);
788 IDispatch_Release(app);
789
790 hr = IWebBrowser2_get_Document(wb, &doc);
791 todo_wine
792 ok(hr == S_OK, "got 0x%08x\n", hr);
793 if (hr == S_OK) {
794 test_dispatch_typeinfo(doc, viewdual_riids);
795 }
796 IWebBrowser2_Release(wb);
797
798 /* IServiceProvider */
799 hr = IDispatch_QueryInterface(disp, &IID_IShellFolderViewDual, (void**)&view);
800 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
801
802 hr = IDispatch_QueryInterface(disp, &IID_IServiceProvider, (void**)&sp);
803 ok(hr == S_OK, "got 0x%08x\n", hr);
804
805 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IShellBrowser, (void**)&sb);
806 ok(hr == S_OK, "got 0x%08x\n", hr);
807
808 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IShellBrowser, (void**)&sb2);
809 ok(hr == S_OK, "got 0x%08x\n", hr);
810 ok(sb == sb2, "got %p, %p\n", sb, sb2);
811
812 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IOleWindow, (void**)&unk);
813 ok(hr == S_OK, "got 0x%08x\n", hr);
814 IUnknown_Release(unk);
815
816 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IExplorerBrowser, (void**)&unk);
817 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
818
819 hr = IShellBrowser_QueryInterface(sb, &IID_IExplorerBrowser, (void**)&unk);
820 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
821
822 hr = IShellBrowser_QueryInterface(sb, &IID_IWebBrowser2, (void**)&unk);
823 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
824
825 hr = IShellBrowser_QueryInterface(sb, &IID_IDispatch, (void**)&unk);
826 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
827
828 hr = IShellBrowser_QueryActiveShellView(sb, &sv);
829 ok(hr == S_OK, "got 0x%08x\n", hr);
830 IShellView_Release(sv);
831
832 IShellBrowser_Release(sb2);
833 IShellBrowser_Release(sb);
834
835 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IUnknown, (void**)&unk);
836 ok(hr == S_OK, "got 0x%08x\n", hr);
837
838 hr = IUnknown_QueryInterface(unk, &IID_IShellBrowser, (void**)&sb2);
839 ok(hr == S_OK, "got 0x%08x\n", hr);
840 IShellBrowser_Release(sb2);
841 IUnknown_Release(unk);
842
843 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IShellView, (void**)&sv);
844 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
845
846 IServiceProvider_Release(sp);
847 IDispatch_Release(disp);
848 }
849
850 disp = (void*)0xdeadbeef;
851 ret = 0xdead;
852 VariantInit(&v);
853 hr = IShellWindows_FindWindowSW(shellwindows, &v, &v, SWC_DESKTOP, &ret, 0, &disp);
854 ok(hr == S_OK || broken(hr == S_FALSE) /* winxp */, "got 0x%08x\n", hr);
855 ok(disp == NULL, "got %p\n", disp);
856 ok(ret != HandleToUlong(hwnd), "got %d\n", ret);
857
858 disp = (void*)0xdeadbeef;
859 ret = 0xdead;
860 V_VT(&v) = VT_I4;
861 V_I4(&v) = cookie;
862 VariantInit(&v2);
863 hr = IShellWindows_FindWindowSW(shellwindows, &v, &v2, SWC_BROWSER, &ret, SWFO_COOKIEPASSED, &disp);
864 todo_wine
865 ok(hr == S_FALSE, "got 0x%08x\n", hr);
866 ok(disp == NULL, "got %p\n", disp);
867 ok(ret == 0, "got %d\n", ret);
868
869 hr = IShellWindows_Revoke(shellwindows, cookie);
870 todo_wine
871 ok(hr == S_OK, "got 0x%08x\n", hr);
872 DestroyWindow(hwnd);
873 IShellWindows_Release(shellwindows);
874 }
875
876 static void test_ParseName(void)
877 {
878 static const WCHAR cadabraW[] = {'c','a','d','a','b','r','a',0};
879 WCHAR pathW[MAX_PATH];
880 IShellDispatch *sd;
881 FolderItem *item;
882 Folder *folder;
883 HRESULT hr;
884 VARIANT v;
885 BSTR str;
886
887 hr = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER,
888 &IID_IShellDispatch, (void**)&sd);
889 ok(hr == S_OK, "got 0x%08x\n", hr);
890
891 GetTempPathW(sizeof(pathW)/sizeof(pathW[0]), pathW);
892 V_VT(&v) = VT_BSTR;
893 V_BSTR(&v) = SysAllocString(pathW);
894 hr = IShellDispatch_NameSpace(sd, v, &folder);
895 ok(hr == S_OK, "got 0x%08x\n", hr);
896 VariantClear(&v);
897
898 item = (void*)0xdeadbeef;
899 hr = Folder_ParseName(folder, NULL, &item);
900 ok(hr == S_FALSE || broken(hr == E_INVALIDARG) /* win2k */, "got 0x%08x\n", hr);
901 ok(item == NULL, "got %p\n", item);
902
903 /* empty name */
904 str = SysAllocStringLen(NULL, 0);
905 item = (void*)0xdeadbeef;
906 hr = Folder_ParseName(folder, str, &item);
907 ok(hr == S_FALSE || broken(hr == E_INVALIDARG) /* win2k */, "got 0x%08x\n", hr);
908 ok(item == NULL, "got %p\n", item);
909 SysFreeString(str);
910
911 /* path doesn't exist */
912 str = SysAllocString(cadabraW);
913 item = (void*)0xdeadbeef;
914 hr = Folder_ParseName(folder, str, &item);
915 ok(hr == S_FALSE || broken(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) /* win2k */,
916 "got 0x%08x\n", hr);
917 ok(item == NULL, "got %p\n", item);
918 SysFreeString(str);
919
920 lstrcatW(pathW, cadabraW);
921 CreateDirectoryW(pathW, NULL);
922
923 str = SysAllocString(cadabraW);
924 item = NULL;
925 hr = Folder_ParseName(folder, str, &item);
926 ok(hr == S_OK, "got 0x%08x\n", hr);
927 ok(item != NULL, "got %p\n", item);
928 SysFreeString(str);
929
930 hr = FolderItem_get_Path(item, &str);
931 ok(hr == S_OK, "got 0x%08x\n", hr);
932 ok(str[0] != 0, "path %s\n", wine_dbgstr_w(str));
933 SysFreeString(str);
934
935 RemoveDirectoryW(pathW);
936 FolderItem_Release(item);
937 Folder_Release(folder);
938 IShellDispatch_Release(sd);
939 }
940
941 static void test_Verbs(void)
942 {
943 FolderItemVerbs *verbs;
944 WCHAR pathW[MAX_PATH];
945 FolderItemVerb *verb;
946 IShellDispatch *sd;
947 FolderItem *item;
948 Folder2 *folder2;
949 Folder *folder;
950 HRESULT hr;
951 LONG count, i;
952 VARIANT v;
953 BSTR str;
954
955 hr = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER,
956 &IID_IShellDispatch, (void**)&sd);
957 ok(hr == S_OK, "got 0x%08x\n", hr);
958
959 GetTempPathW(sizeof(pathW)/sizeof(pathW[0]), pathW);
960 V_VT(&v) = VT_BSTR;
961 V_BSTR(&v) = SysAllocString(pathW);
962 hr = IShellDispatch_NameSpace(sd, v, &folder);
963 ok(hr == S_OK, "got 0x%08x\n", hr);
964 VariantClear(&v);
965
966 hr = Folder_QueryInterface(folder, &IID_Folder2, (void**)&folder2);
967 ok(hr == S_OK, "got 0x%08x\n", hr);
968 Folder_Release(folder);
969
970 hr = Folder2_get_Self(folder2, &item);
971 ok(hr == S_OK, "got 0x%08x\n", hr);
972 Folder2_Release(folder2);
973
974 if (0) { /* crashes on some systems */
975 hr = FolderItem_Verbs(item, NULL);
976 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
977 }
978 hr = FolderItem_Verbs(item, &verbs);
979 ok(hr == S_OK, "got 0x%08x\n", hr);
980
981 if (0) { /* crashes on winxp/win2k3 */
982 hr = FolderItemVerbs_get_Count(verbs, NULL);
983 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
984 }
985 count = 0;
986 hr = FolderItemVerbs_get_Count(verbs, &count);
987 ok(hr == S_OK, "got 0x%08x\n", hr);
988 ok(count > 0, "got count %d\n", count);
989
990 if (0) { /* crashes on winxp/win2k3 */
991 V_VT(&v) = VT_I4;
992 V_I4(&v) = 0;
993 hr = FolderItemVerbs_Item(verbs, v, NULL);
994 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
995 }
996 /* there's always one item more, so you can access [0,count],
997 instead of actual [0,count) */
998 for (i = 0; i <= count; i++) {
999 V_VT(&v) = VT_I4;
1000 V_I4(&v) = i;
1001 hr = FolderItemVerbs_Item(verbs, v, &verb);
1002 ok(hr == S_OK, "got 0x%08x\n", hr);
1003 hr = FolderItemVerb_get_Name(verb, &str);
1004 ok(hr == S_OK, "got 0x%08x\n", hr);
1005 ok(str != NULL, "%d: name %s\n", i, wine_dbgstr_w(str));
1006 if (i == count)
1007 ok(str[0] == 0, "%d: got teminating item %s\n", i, wine_dbgstr_w(str));
1008
1009 SysFreeString(str);
1010 FolderItemVerb_Release(verb);
1011 }
1012
1013 V_VT(&v) = VT_I4;
1014 V_I4(&v) = count+1;
1015 verb = NULL;
1016 hr = FolderItemVerbs_Item(verbs, v, &verb);
1017 ok(hr == S_OK, "got 0x%08x\n", hr);
1018 ok(verb == NULL, "got %p\n", verb);
1019
1020 FolderItemVerbs_Release(verbs);
1021 FolderItem_Release(item);
1022 IShellDispatch_Release(sd);
1023 }
1024
1025 static void test_ShellExecute(void)
1026 {
1027 HRESULT hr;
1028 IShellDispatch2 *sd;
1029 BSTR name;
1030 VARIANT args, dir, op, show;
1031
1032 static const WCHAR regW[] = {'r','e','g',0};
1033
1034 hr = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER,
1035 &IID_IShellDispatch2, (void**)&sd);
1036 if (hr != S_OK)
1037 {
1038 win_skip("IShellDispatch2 not supported\n");
1039 return;
1040 }
1041
1042 VariantInit(&args);
1043 VariantInit(&dir);
1044 VariantInit(&op);
1045 VariantInit(&show);
1046
1047 V_VT(&show) = VT_I4;
1048 V_I4(&show) = 0;
1049
1050 name = SysAllocString(regW);
1051
1052 hr = IShellDispatch2_ShellExecute(sd, name, args, dir, op, show);
1053 ok(hr == S_OK, "ShellExecute failed: %08x\n", hr);
1054
1055 /* test invalid value for show */
1056 V_VT(&show) = VT_BSTR;
1057 V_BSTR(&show) = name;
1058
1059 hr = IShellDispatch2_ShellExecute(sd, name, args, dir, op, show);
1060 ok(hr == S_OK, "ShellExecute failed: %08x\n", hr);
1061
1062 SysFreeString(name);
1063 }
1064
1065 START_TEST(shelldispatch)
1066 {
1067 HRESULT r;
1068
1069 r = CoInitialize(NULL);
1070 ok(SUCCEEDED(r), "CoInitialize failed: %08x\n", r);
1071 if (FAILED(r))
1072 return;
1073
1074 init_function_pointers();
1075 test_namespace();
1076 test_items();
1077 test_service();
1078 test_ShellFolderViewDual();
1079 test_ShellWindows();
1080 test_ParseName();
1081 test_Verbs();
1082 test_ShellExecute();
1083
1084 CoUninitialize();
1085 }