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