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 }
1086