1 /*
2  * Tests for special shell folders
3  *
4  * Copyright 2008 Robert Shearman for CodeWeavers
5  * Copyright 2008 Owen Rudge
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #include <stdarg.h>
23 #include <stdio.h>
24 
25 #define COBJMACROS
26 #ifndef __REACTOS__
27 #define NONAMELESSUNION
28 #define NONAMELESSSTRUCT
29 #endif
30 
31 #define WIN32_LEAN_AND_MEAN
32 #include <windows.h>
33 #include "shellapi.h"
34 #include "shlwapi.h"
35 #include "shlobj.h"
36 
37 #include "wine/test.h"
38 
39 static inline BOOL SHELL_OsIsUnicode(void)
40 {
41     return !(GetVersion() & 0x80000000);
42 }
43 
44 /* Tests for My Network Places */
45 static void test_parse_for_entire_network(void)
46 {
47     static WCHAR my_network_places_path[] = {
48         ':',':','{','2','0','8','D','2','C','6','0','-','3','A','E','A','-',
49                     '1','0','6','9','-','A','2','D','7','-','0','8','0','0','2','B','3','0','3','0','9','D','}', 0 };
50     static WCHAR entire_network_path[] = {
51         ':',':','{','2','0','8','D','2','C','6','0','-','3','A','E','A','-',
52                     '1','0','6','9','-','A','2','D','7','-','0','8','0','0','2','B','3','0','3','0','9','D',
53                 '}','\\','E','n','t','i','r','e','N','e','t','w','o','r','k',0 };
54     IShellFolder *psfDesktop;
55     HRESULT hr;
56     DWORD eaten = 0xdeadbeef;
57     LPITEMIDLIST pidl;
58     DWORD attr = ~0;
59     DWORD expected_attr;
60 
61     hr = SHGetDesktopFolder(&psfDesktop);
62     ok(hr == S_OK, "SHGetDesktopFolder failed with error 0x%x\n", hr);
63 
64     hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, my_network_places_path, &eaten, &pidl, &attr);
65     ok(hr == S_OK, "IShellFolder_ParseDisplayName failed with error 0x%x\n", hr);
66     todo_wine
67     ok(eaten == 0xdeadbeef, "eaten should not have been set to %u\n", eaten);
68     expected_attr = SFGAO_HASSUBFOLDER|SFGAO_FOLDER|SFGAO_FILESYSANCESTOR|SFGAO_DROPTARGET|SFGAO_HASPROPSHEET|SFGAO_CANRENAME|SFGAO_CANLINK;
69     todo_wine
70     ok((attr == expected_attr) || /* Win9x, NT4 */
71        (attr == (expected_attr | SFGAO_STREAM)) || /* W2K */
72        (attr == (expected_attr | SFGAO_CANDELETE)) || /* XP, W2K3 */
73        (attr == (expected_attr | SFGAO_CANDELETE | SFGAO_NONENUMERATED)), /* Vista */
74        "Unexpected attributes : %08x\n", attr);
75 
76     ILFree(pidl);
77 
78     /* Start clean again */
79     eaten = 0xdeadbeef;
80     attr = ~0;
81 
82     hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, entire_network_path, &eaten, &pidl, &attr);
83     IShellFolder_Release(psfDesktop);
84     if (hr == HRESULT_FROM_WIN32(ERROR_BAD_NET_NAME) ||
85         hr == HRESULT_FROM_WIN32(ERROR_NO_NET_OR_BAD_PATH) ||
86         hr == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER))
87     {
88         win_skip("'EntireNetwork' is not available on Win9x, NT4 and Vista\n");
89         return;
90     }
91     ok(hr == S_OK, "IShellFolder_ParseDisplayName failed with error 0x%x\n", hr);
92     todo_wine
93     ok(eaten == 0xdeadbeef, "eaten should not have been set to %u\n", eaten);
94     expected_attr = SFGAO_HASSUBFOLDER|SFGAO_FOLDER|SFGAO_FILESYSANCESTOR|SFGAO_HASPROPSHEET|SFGAO_CANLINK;
95     todo_wine
96     ok(attr == expected_attr || /* winme, nt4 */
97        attr == (expected_attr | SFGAO_STREAM) || /* win2k */
98        attr == (expected_attr | SFGAO_STORAGEANCESTOR),  /* others */
99        "attr should be 0x%x, not 0x%x\n", expected_attr, attr);
100 
101     ILFree(pidl);
102 }
103 
104 /* Tests for Control Panel */
105 static void test_parse_for_control_panel(void)
106 {
107     /* path of My Computer\Control Panel */
108     static WCHAR control_panel_path[] = {
109         ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-','A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}','\\',
110         ':',':','{','2','1','E','C','2','0','2','0','-','3','A','E','A','-','1','0','6','9','-','A','2','D','D','-','0','8','0','0','2','B','3','0','3','0','9','D','}', 0 };
111     IShellFolder *psfDesktop;
112     HRESULT hr;
113     DWORD eaten = 0xdeadbeef;
114     LPITEMIDLIST pidl;
115     DWORD attr = ~0;
116 
117     hr = SHGetDesktopFolder(&psfDesktop);
118     ok(hr == S_OK, "SHGetDesktopFolder failed with error 0x%x\n", hr);
119 
120     hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, control_panel_path, &eaten, &pidl, &attr);
121     ok(hr == S_OK, "IShellFolder_ParseDisplayName failed with error 0x%x\n", hr);
122     todo_wine ok(eaten == 0xdeadbeef, "eaten should not have been set to %u\n", eaten);
123     todo_wine
124     ok((attr == (SFGAO_CANLINK | SFGAO_FOLDER)) || /* Win9x, NT4 */
125        (attr == (SFGAO_CANLINK | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_STREAM)) || /* W2K */
126        (attr == (SFGAO_CANLINK | SFGAO_FOLDER | SFGAO_HASSUBFOLDER)) || /* W2K, XP, W2K3 */
127        (attr == (SFGAO_CANLINK | SFGAO_NONENUMERATED)) || /* Vista */
128        (attr == SFGAO_CANLINK), /* Vista, W2K8 */
129        "Unexpected attributes : %08x\n", attr);
130 
131     ILFree(pidl);
132     IShellFolder_Release(psfDesktop);
133 }
134 
135 static void test_printers_folder(void)
136 {
137     IShellFolder2 *folder;
138     IPersistFolder2 *pf;
139     SHELLDETAILS details;
140     SHCOLSTATEF state;
141     LPITEMIDLIST pidl1, pidl2;
142     HRESULT hr;
143     INT i;
144 
145     CoInitialize( NULL );
146 
147     hr = CoCreateInstance(&CLSID_Printers, NULL, CLSCTX_INPROC_SERVER, &IID_IShellFolder2, (void**)&folder);
148     if (hr != S_OK)
149     {
150         win_skip("Failed to created IShellFolder2 for Printers folder\n");
151         CoUninitialize();
152         return;
153     }
154 
155 if (0)
156 {
157     /* crashes on XP */
158     IShellFolder2_GetDetailsOf(folder, NULL, 0, NULL);
159     IShellFolder2_GetDefaultColumnState(folder, 0, NULL);
160     IPersistFolder2_GetCurFolder(pf, NULL);
161 }
162 
163     /* 5 columns defined */
164     hr = IShellFolder2_GetDetailsOf(folder, NULL, 6, &details);
165     ok(hr == E_NOTIMPL, "got 0x%08x\n", hr);
166 
167     hr = IShellFolder2_GetDefaultColumnState(folder, 6, &state);
168     ok(broken(hr == E_NOTIMPL) || hr == E_INVALIDARG /* Win7 */, "got 0x%08x\n", hr);
169 
170     details.str.pOleStr = NULL;
171     hr = IShellFolder2_GetDetailsOf(folder, NULL, 0, &details);
172     ok(hr == S_OK || broken(hr == E_NOTIMPL) /* W2K */, "got 0x%08x\n", hr);
173     if (SHELL_OsIsUnicode()) SHFree(details.str.pOleStr);
174 
175     /* test every column if method is implemented */
176     if (hr == S_OK)
177     {
178         ok(details.str.uType == STRRET_WSTR, "got %d\n", details.str.uType);
179 
180         for(i = 0; i < 6; i++)
181         {
182             hr = IShellFolder2_GetDetailsOf(folder, NULL, i, &details);
183             ok(hr == S_OK, "got 0x%08x\n", hr);
184 
185             /* all columns are left-aligned */
186             ok(details.fmt == LVCFMT_LEFT, "got 0x%x\n", details.fmt);
187             /* can't be on w9x at this point, IShellFolder2 unsupported there,
188                check present for running Wine with w9x setup */
189             if (SHELL_OsIsUnicode()) SHFree(details.str.pOleStr);
190 
191             hr = IShellFolder2_GetDefaultColumnState(folder, i, &state);
192             ok(hr == S_OK, "got 0x%08x\n", hr);
193             /* all columns are string except document count */
194             if (i == 1)
195                 ok(state == (SHCOLSTATE_TYPE_INT | SHCOLSTATE_ONBYDEFAULT), "got 0x%x\n", state);
196             else
197                 ok(state == (SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT), "got 0x%x\n", state);
198         }
199     }
200 
201     /* default pidl */
202     hr = IShellFolder2_QueryInterface(folder, &IID_IPersistFolder2, (void**)&pf);
203     ok(hr == S_OK, "got 0x%08x\n", hr);
204 
205     /* not initialized */
206     pidl1 = (void*)0xdeadbeef;
207     hr = IPersistFolder2_GetCurFolder(pf, &pidl1);
208     ok(hr == S_FALSE, "got 0x%08x\n", hr);
209     ok(pidl1 == NULL, "got %p\n", pidl1);
210 
211     hr = SHGetSpecialFolderLocation(NULL, CSIDL_PRINTERS, &pidl2);
212     ok(hr == S_OK, "got 0x%08x\n", hr);
213 
214     hr = IPersistFolder2_Initialize(pf, pidl2);
215     ok(hr == S_OK, "got 0x%08x\n", hr);
216 
217     hr = IPersistFolder2_GetCurFolder(pf, &pidl1);
218     ok(hr == S_OK, "got 0x%08x\n", hr);
219 
220     ok(ILIsEqual(pidl1, pidl2), "expected same PIDL\n");
221     IPersistFolder2_Release(pf);
222 
223     ILFree(pidl1);
224     ILFree(pidl2);
225     IShellFolder2_Release(folder);
226 
227     CoUninitialize();
228 }
229 
230 static void test_desktop_folder(void)
231 {
232     IShellFolder *psf;
233     HRESULT hr;
234 
235     hr = SHGetDesktopFolder(&psf);
236     ok(hr == S_OK, "Got %x\n", hr);
237 
238     hr = IShellFolder_QueryInterface(psf, &IID_IShellFolder, NULL);
239     ok(hr == E_POINTER, "Got %x\n", hr);
240 
241     IShellFolder_Release(psf);
242 }
243 
244 static void test_desktop_displaynameof(void)
245 {
246     static WCHAR MyComputer[]  = { ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-','A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}', 0 };
247     static WCHAR MyDocuments[] = { ':',':','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-','1','1','D','0','-','9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}', 0 };
248     static WCHAR RecycleBin[]  = { ':',':','{','6','4','5','F','F','0','4','0','-','5','0','8','1','-','1','0','1','B','-','9','F','0','8','-','0','0','A','A','0','0','2','F','9','5','4','E','}', 0 };
249     static WCHAR ControlPanel[]= { ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-','A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}','\\',
250                                    ':',':','{','2','1','E','C','2','0','2','0','-','3','A','E','A','-','1','0','6','9','-','A','2','D','D','-','0','8','0','0','2','B','3','0','3','0','9','D','}', 0 };
251     static WCHAR *folders[] = { MyComputer, MyDocuments, RecycleBin, ControlPanel };
252     IShellFolder *desktop;
253     ITEMIDLIST *pidl;
254     STRRET strret;
255     DWORD eaten;
256     HRESULT hr;
257     UINT i;
258 
259     hr = SHGetDesktopFolder(&desktop);
260     ok(hr == S_OK, "SHGetDesktopFolder failed with error 0x%08x\n", hr);
261     if (FAILED(hr)) return;
262 
263     for (i = 0; i < ARRAY_SIZE(folders); i++)
264     {
265         WCHAR name1[MAX_PATH], name2[MAX_PATH];
266 
267         hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, folders[i], &eaten, &pidl, NULL);
268         ok(hr == S_OK, "IShellFolder::ParseDisplayName failed with error 0x%08x\n", hr);
269         if (FAILED(hr)) continue;
270 
271         hr = IShellFolder_GetDisplayNameOf(desktop, pidl, SHGDN_INFOLDER, &strret);
272         ok(hr == S_OK, "IShellFolder::GetDisplayNameOf failed with error 0x%08x\n", hr);
273         hr = StrRetToBufW(&strret, pidl, name1, ARRAY_SIZE(name1));
274         ok(hr == S_OK, "StrRetToBuf failed with error 0x%08x\n", hr);
275 
276         hr = IShellFolder_GetDisplayNameOf(desktop, pidl, SHGDN_INFOLDER | SHGDN_FORPARSING | SHGDN_FORADDRESSBAR, &strret);
277         ok(hr == S_OK, "IShellFolder::GetDisplayNameOf failed with error 0x%08x\n", hr);
278         hr = StrRetToBufW(&strret, pidl, name2, ARRAY_SIZE(name2));
279         ok(hr == S_OK, "StrRetToBuf failed with error 0x%08x\n", hr);
280 
281         ok(!lstrcmpW(name1, name2), "the display names are not equal: %s vs %s\n", wine_dbgstr_w(name1), wine_dbgstr_w(name2));
282         ok(name1[0] != ':' || name1[1] != ':', "display name is a GUID: %s\n", wine_dbgstr_w(name1));
283 
284         hr = IShellFolder_GetDisplayNameOf(desktop, pidl, SHGDN_INFOLDER | SHGDN_FORPARSING, &strret);
285         ok(hr == S_OK, "IShellFolder::GetDisplayNameOf failed with error 0x%08x\n", hr);
286         hr = StrRetToBufW(&strret, pidl, name1, ARRAY_SIZE(name1));
287         ok(hr == S_OK, "StrRetToBuf failed with error 0x%08x\n", hr);
288 
289         ok(lstrcmpW(name1, name2), "the display names are equal: %s\n", wine_dbgstr_w(name1));
290         ok(name1[0] == ':' && name1[1] == ':', "display name is not a GUID: %s\n", wine_dbgstr_w(name1));
291 
292         ILFree(pidl);
293     }
294     IShellFolder_Release(desktop);
295 }
296 
297 START_TEST(shfldr_special)
298 {
299     test_parse_for_entire_network();
300     test_parse_for_control_panel();
301     test_printers_folder();
302     test_desktop_folder();
303     test_desktop_displaynameof();
304 }
305