1 /*
2  * Unit test of the IShellFolder functions.
3  *
4  * Copyright 2004 Vitaliy Margolen
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 <stdarg.h>
22 #include <stdio.h>
23 
24 #define COBJMACROS
25 #define CONST_VTABLE
26 
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wtypes.h"
30 #include "shellapi.h"
31 
32 
33 #include "shlguid.h"
34 #include "shlobj.h"
35 #include "shobjidl.h"
36 #include "shlwapi.h"
37 #include "ocidl.h"
38 #include "oleauto.h"
39 
40 #include "wine/heap.h"
41 #include "wine/test.h"
42 
43 #include <initguid.h>
44 DEFINE_GUID(IID_IParentAndItem, 0xB3A4B685, 0xB685, 0x4805, 0x99,0xD9, 0x5D,0xEA,0xD2,0x87,0x32,0x36);
45 DEFINE_GUID(CLSID_ShellDocObjView, 0xe7e4bc40, 0xe76a, 0x11ce, 0xa9,0xbb, 0x00,0xaa,0x00,0x4a,0xe8,0x37);
46 
47 static IMalloc *ppM;
48 
49 static HRESULT (WINAPI *pSHCreateItemFromIDList)(PCIDLIST_ABSOLUTE pidl, REFIID riid, void **ppv);
50 static HRESULT (WINAPI *pSHCreateItemFromParsingName)(PCWSTR,IBindCtx*,REFIID,void**);
51 static HRESULT (WINAPI *pSHCreateItemFromRelativeName)(IShellItem*,PCWSTR,IBindCtx*,REFIID,void**);
52 static HRESULT (WINAPI *pSHCreateItemInKnownFolder)(REFKNOWNFOLDERID,DWORD,PCWSTR,REFIID,void **);
53 static HRESULT (WINAPI *pSHCreateShellItem)(LPCITEMIDLIST,IShellFolder*,LPCITEMIDLIST,IShellItem**);
54 static HRESULT (WINAPI *pSHCreateShellItemArray)(LPCITEMIDLIST,IShellFolder*,UINT,LPCITEMIDLIST*,IShellItemArray**);
55 static HRESULT (WINAPI *pSHCreateShellItemArrayFromIDLists)(UINT, PCIDLIST_ABSOLUTE*, IShellItemArray**);
56 static HRESULT (WINAPI *pSHCreateShellItemArrayFromDataObject)(IDataObject*, REFIID, void **);
57 static HRESULT (WINAPI *pSHCreateShellItemArrayFromShellItem)(IShellItem*, REFIID, void **);
58 static HRESULT (WINAPI *pSHGetKnownFolderPath)(REFKNOWNFOLDERID,DWORD,HANDLE,PWSTR*);
59 static HRESULT (WINAPI *pSHGetNameFromIDList)(PCIDLIST_ABSOLUTE,SIGDN,PWSTR*);
60 static HRESULT (WINAPI *pSHGetItemFromDataObject)(IDataObject*,DATAOBJ_GET_ITEM_FLAGS,REFIID,void**);
61 static HRESULT (WINAPI *pSHGetIDListFromObject)(IUnknown*, PIDLIST_ABSOLUTE*);
62 static HRESULT (WINAPI *pSHGetItemFromObject)(IUnknown*,REFIID,void**);
63 static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
64 static HRESULT (WINAPI *pSHCreateDefaultContextMenu)(const DEFCONTEXTMENU*,REFIID,void**);
65 static BOOL (WINAPI *pSHGetPathFromIDListEx)(PCIDLIST_ABSOLUTE,WCHAR*,DWORD,GPFIDL_FLAGS);
66 #ifdef __REACTOS__
67 typedef SHFOLDERCUSTOMSETTINGSW SHFOLDERCUSTOMSETTINGS, *LPSHFOLDERCUSTOMSETTINGS;
68 #endif
69 static HRESULT (WINAPI *pSHGetSetFolderCustomSettings)(LPSHFOLDERCUSTOMSETTINGS,PCWSTR,DWORD);
70 
make_wstr(const char * str)71 static WCHAR *make_wstr(const char *str)
72 {
73     WCHAR *ret;
74     int len;
75 
76     if (!str || !str[0])
77         return NULL;
78 
79     len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
80     if(!len || len < 0)
81         return NULL;
82 
83     ret = heap_alloc(len * sizeof(WCHAR));
84     if(!ret)
85         return NULL;
86 
87     MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
88     return ret;
89 }
90 
strcmp_wa(LPCWSTR strw,const char * stra)91 static int strcmp_wa(LPCWSTR strw, const char *stra)
92 {
93     CHAR buf[512];
94     WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL);
95     return lstrcmpA(stra, buf);
96 }
97 
init_function_pointers(void)98 static void init_function_pointers(void)
99 {
100     HMODULE hmod;
101     HRESULT hr;
102     void *ptr;
103 
104     hmod = GetModuleHandleA("shell32.dll");
105 
106 #define MAKEFUNC(f) (p##f = (void*)GetProcAddress(hmod, #f))
107     MAKEFUNC(SHCreateItemFromIDList);
108     MAKEFUNC(SHCreateItemFromParsingName);
109     MAKEFUNC(SHCreateItemFromRelativeName);
110     MAKEFUNC(SHCreateItemInKnownFolder);
111     MAKEFUNC(SHCreateShellItem);
112     MAKEFUNC(SHCreateShellItemArray);
113     MAKEFUNC(SHCreateShellItemArrayFromIDLists);
114     MAKEFUNC(SHCreateShellItemArrayFromDataObject);
115     MAKEFUNC(SHCreateShellItemArrayFromShellItem);
116     MAKEFUNC(SHGetKnownFolderPath);
117     MAKEFUNC(SHGetNameFromIDList);
118     MAKEFUNC(SHGetItemFromDataObject);
119     MAKEFUNC(SHGetIDListFromObject);
120     MAKEFUNC(SHGetItemFromObject);
121     MAKEFUNC(SHCreateDefaultContextMenu);
122     MAKEFUNC(SHGetPathFromIDListEx);
123     MAKEFUNC(SHGetSetFolderCustomSettings);
124 #undef MAKEFUNC
125 
126     /* test named exports */
127     ptr = GetProcAddress(hmod, "ILFree");
128     ok(broken(ptr == 0) || ptr != 0, "expected named export for ILFree\n");
129     if (ptr)
130     {
131 #define TESTNAMED(f) \
132     ptr = (void*)GetProcAddress(hmod, #f); \
133     ok(ptr != 0, "expected named export for " #f "\n");
134 
135         TESTNAMED(ILAppendID);
136         TESTNAMED(ILClone);
137         TESTNAMED(ILCloneFirst);
138         TESTNAMED(ILCombine);
139         TESTNAMED(ILCreateFromPath);
140         TESTNAMED(ILCreateFromPathA);
141         TESTNAMED(ILCreateFromPathW);
142         TESTNAMED(ILFindChild);
143         TESTNAMED(ILFindLastID);
144         TESTNAMED(ILGetNext);
145         TESTNAMED(ILGetSize);
146         TESTNAMED(ILIsEqual);
147         TESTNAMED(ILIsParent);
148         TESTNAMED(ILRemoveLastID);
149         TESTNAMED(ILSaveToStream);
150 #undef TESTNAMED
151     }
152 
153     hmod = GetModuleHandleA("kernel32.dll");
154     pIsWow64Process = (void*)GetProcAddress(hmod, "IsWow64Process");
155 
156     hr = SHGetMalloc(&ppM);
157     ok(hr == S_OK, "SHGetMalloc failed %08x\n", hr);
158 }
159 
160 /* Based on PathAddBackslashW from dlls/shlwapi/path.c */
myPathAddBackslashW(LPWSTR lpszPath)161 static LPWSTR myPathAddBackslashW( LPWSTR lpszPath )
162 {
163   size_t iLen;
164 
165   if (!lpszPath || (iLen = lstrlenW(lpszPath)) >= MAX_PATH)
166     return NULL;
167 
168   if (iLen)
169   {
170     lpszPath += iLen;
171     if (lpszPath[-1] != '\\')
172     {
173       *lpszPath++ = '\\';
174       *lpszPath = '\0';
175     }
176   }
177   return lpszPath;
178 }
179 
180 static struct
181 {
182     WCHAR path[MAX_PATH];
183     HRESULT hr;
184     int todo;
185 } parse_tests[] = {
186     {{'c',':','\\',0}, S_OK},
187     {{'c',':','\\','\\',0}, E_INVALIDARG, 1},
188     {{'c',':','\\','f','a','k','e',0}, 0x80070002}, /* ERROR_FILE_NOT_FOUND */
189     {{'c',':','f','a','k','e',0}, E_INVALIDARG, 1},
190     {{'c',':','/',0}, E_INVALIDARG, 1},
191     {{'c',':','\\','w','i','n','d','o','w','s',0}, S_OK},
192     {{'c',':','\\','w','i','n','d','o','w','s','\\',0}, S_OK},
193     {{'c',':','\\','w','i','n','d','o','w','s','\\','.',0}, E_INVALIDARG, 1},
194     {{'c',':','\\','w','i','n','d','o','w','s','\\','.','.',0}, E_INVALIDARG, 1},
195     {{'.',0}, E_INVALIDARG, 1},
196     {{'.','.',0}, E_INVALIDARG, 1},
197     {{'t','e','s','t',0}, 0x80070002},
198     {{'t','e','s','t','\\',0}, 0x80070002},
199     {{'s','u','b','\\','d','i','r',0}, 0x80070002},
200     {{'s','u','b','/','d','i','r',0}, E_INVALIDARG, 1},
201     {{'h','t','t','p',':',0}, S_OK, 1},
202     {{'h','t','t','p',':','t','e','s','t',0}, S_OK, 1},
203     {{'h','t','t','p',':','\\','t','e','s','t',0}, S_OK, 1},
204     {{'x','x',':',0}, S_OK, 1},
205 };
206 
test_ParseDisplayName(void)207 static void test_ParseDisplayName(void)
208 {
209     static WCHAR testdirW[] = {'p','a','r','s','e','t','e','s','t',0};
210     static WCHAR backslashW[] = {'\\',0};
211     WCHAR buffer[MAX_PATH], buffer2[MAX_PATH];
212     IShellFolder *desktop;
213     ITEMIDLIST *pidl;
214     HRESULT hr;
215     BOOL bRes;
216     int i;
217 
218     hr = SHGetDesktopFolder(&desktop);
219     ok(hr == S_OK, "Expected SHGetDesktopFolder to return S_OK, got 0x%08x\n", hr);
220 
221     hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, NULL, NULL, &pidl, NULL);
222     ok(hr == E_INVALIDARG, "got %#x\n", hr);
223 
224     for (i = 0; i < ARRAY_SIZE(parse_tests); i++)
225     {
226         hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, parse_tests[i].path, NULL, &pidl, NULL);
227 todo_wine_if(parse_tests[i].todo)
228         ok(hr == parse_tests[i].hr, "%s: expected %#x, got %#x\n",
229             wine_dbgstr_w(parse_tests[i].path), parse_tests[i].hr, hr);
230         if (SUCCEEDED(hr))
231             CoTaskMemFree(pidl);
232     }
233 
234     /* I thought that perhaps the DesktopFolder's ParseDisplayName would recognize the
235      * path corresponding to CSIDL_PERSONAL and return a CLSID_MyDocuments PIDL. Turns
236      * out it doesn't. The magic seems to happen in the file dialogs, then. */
237 
238     bRes = SHGetSpecialFolderPathW(NULL, buffer, CSIDL_PERSONAL, FALSE);
239     ok(bRes, "SHGetSpecialFolderPath(CSIDL_PERSONAL) failed! %u\n", GetLastError());
240 
241     hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, buffer, NULL, &pidl, 0);
242     ok(hr == S_OK, "DesktopFolder->ParseDisplayName failed. hr = %08x.\n", hr);
243 
244     ok(ILFindLastID(pidl)->mkid.abID[0] == 0x31,
245        "Last pidl should be of type PT_FOLDER, but is: %02x\n",
246        ILFindLastID(pidl)->mkid.abID[0]);
247     CoTaskMemFree(pidl);
248 
249     /* Relative paths are interpreted relative to the desktop. */
250     GetTempPathW(ARRAY_SIZE(buffer), buffer);
251     GetLongPathNameW(buffer, buffer, ARRAY_SIZE(buffer));
252     SetCurrentDirectoryW(buffer);
253     CreateDirectoryW(testdirW, NULL);
254 
255     hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, testdirW, NULL, &pidl, NULL);
256     ok(hr == 0x80070002, "got %#x\n", hr);
257 
258     RemoveDirectoryW(testdirW);
259 
260     hr = SHGetSpecialFolderPathW(NULL, buffer, CSIDL_DESKTOP, FALSE);
261     ok(hr == S_FALSE, "got %#x\n", hr);
262     SetCurrentDirectoryW(buffer);
263     CreateDirectoryW(testdirW, NULL);
264 
265     hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, testdirW, NULL, &pidl, NULL);
266     ok(hr == S_OK, "got %#x\n", hr);
267 
268     ok(SHGetPathFromIDListW(pidl, buffer2), "SHGetPathFromIDList failed\n");
269     lstrcatW(buffer, backslashW);
270     lstrcatW(buffer, testdirW);
271     ok(!lstrcmpW(buffer, buffer2), "expected %s, got %s\n", wine_dbgstr_w(buffer), wine_dbgstr_w(buffer2));
272 
273     RemoveDirectoryW(testdirW);
274     CoTaskMemFree(pidl);
275 
276     IShellFolder_Release(desktop);
277 }
278 
279 /* creates a file with the specified name for tests */
CreateTestFile(const CHAR * name)280 static void CreateTestFile(const CHAR *name)
281 {
282     HANDLE file;
283     DWORD written;
284 
285     file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
286     if (file != INVALID_HANDLE_VALUE)
287     {
288 	WriteFile(file, name, strlen(name), &written, NULL);
289 	WriteFile(file, "\n", strlen("\n"), &written, NULL);
290 	CloseHandle(file);
291     }
292 }
293 
294 
295 /* initializes the tests */
CreateFilesFolders(void)296 static void CreateFilesFolders(void)
297 {
298     CreateDirectoryA(".\\testdir", NULL);
299     CreateDirectoryA(".\\testdir\\test.txt", NULL);
300     CreateTestFile  (".\\testdir\\test1.txt ");
301     CreateTestFile  (".\\testdir\\test2.txt ");
302     CreateTestFile  (".\\testdir\\test3.txt ");
303     CreateDirectoryA(".\\testdir\\testdir2 ", NULL);
304     CreateDirectoryA(".\\testdir\\testdir2\\subdir", NULL);
305 }
306 
307 /* cleans after tests */
Cleanup(void)308 static void Cleanup(void)
309 {
310     DeleteFileA(".\\testdir\\test1.txt");
311     DeleteFileA(".\\testdir\\test2.txt");
312     DeleteFileA(".\\testdir\\test3.txt");
313     RemoveDirectoryA(".\\testdir\\test.txt");
314     RemoveDirectoryA(".\\testdir\\testdir2\\subdir");
315     RemoveDirectoryA(".\\testdir\\testdir2");
316     RemoveDirectoryA(".\\testdir");
317 }
318 
319 
320 /* perform test */
test_EnumObjects(IShellFolder * iFolder)321 static void test_EnumObjects(IShellFolder *iFolder)
322 {
323     IEnumIDList *iEnumList;
324     LPITEMIDLIST newPIDL, idlArr[10];
325     ULONG NumPIDLs;
326     int i=0, j;
327     HRESULT hr;
328 
329     static const WORD iResults [5][5] =
330     {
331 	{ 0,-1,-1,-1,-1},
332 	{ 1, 0,-1,-1,-1},
333 	{ 1, 1, 0,-1,-1},
334 	{ 1, 1, 1, 0,-1},
335 	{ 1, 1, 1, 1, 0}
336     };
337 
338 #define SFGAO_testfor SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | SFGAO_CAPABILITYMASK
339     /* Don't test for SFGAO_HASSUBFOLDER since we return real state and native cached */
340     static const ULONG attrs[5] =
341     {
342         SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
343         SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
344         SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
345         SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
346         SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
347     };
348     static const ULONG full_attrs[5] =
349     {
350         SFGAO_CAPABILITYMASK | SFGAO_STORAGE | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
351         SFGAO_CAPABILITYMASK | SFGAO_STORAGE | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
352         SFGAO_CAPABILITYMASK | SFGAO_STREAM | SFGAO_FILESYSTEM,
353         SFGAO_CAPABILITYMASK | SFGAO_STREAM | SFGAO_FILESYSTEM,
354         SFGAO_CAPABILITYMASK | SFGAO_STREAM | SFGAO_FILESYSTEM,
355     };
356 
357     hr = IShellFolder_EnumObjects(iFolder, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &iEnumList);
358     ok(hr == S_OK, "EnumObjects failed %08x\n", hr);
359 
360     /* This is to show that, contrary to what is said on MSDN, on IEnumIDList::Next,
361      * the filesystem shellfolders return S_OK even if less than 'celt' items are
362      * returned (in contrast to S_FALSE). We have to do it in a loop since WinXP
363      * only ever returns a single entry per call. */
364     while (IEnumIDList_Next(iEnumList, 10-i, &idlArr[i], &NumPIDLs) == S_OK)
365         i += NumPIDLs;
366     ok (i == 5, "i: %d\n", i);
367 
368     hr = IEnumIDList_Release(iEnumList);
369     ok(hr == S_OK, "IEnumIDList_Release failed %08x\n", hr);
370 
371     /* Sort them first in case of wrong order from system */
372     for (i=0;i<5;i++) for (j=0;j<5;j++)
373         if ((SHORT)IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]) < 0)
374 	{
375             newPIDL = idlArr[i];
376             idlArr[i] = idlArr[j];
377             idlArr[j] = newPIDL;
378         }
379 
380     for (i=0;i<5;i++) for (j=0;j<5;j++)
381     {
382         hr = IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]);
383         ok(hr == iResults[i][j], "Got %x expected [%d]-[%d]=%x\n", hr, i, j, iResults[i][j]);
384     }
385 
386 
387     for (i = 0; i < 5; i++)
388     {
389         SFGAOF flags;
390 #define SFGAO_VISTA SFGAO_DROPTARGET | SFGAO_CANLINK | SFGAO_CANCOPY
391         /* Native returns all flags no matter what we ask for */
392         flags = SFGAO_CANCOPY;
393         hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
394         flags &= SFGAO_testfor;
395         ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
396         ok(flags == (attrs[i]) ||
397            flags == ((attrs[i] & ~SFGAO_CAPABILITYMASK) | SFGAO_VISTA), /* Vista and higher */
398            "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
399 
400         flags = SFGAO_testfor;
401         hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
402         flags &= SFGAO_testfor;
403         ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
404         ok(flags == attrs[i], "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
405 
406         flags = ~0u;
407         hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
408         ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
409         ok((flags & ~(SFGAO_HASSUBFOLDER|SFGAO_COMPRESSED)) == full_attrs[i], "%d: got %08x expected %08x\n", i, flags, full_attrs[i]);
410     }
411 
412     for (i=0;i<5;i++)
413         IMalloc_Free(ppM, idlArr[i]);
414 }
415 
test_BindToObject(void)416 static void test_BindToObject(void)
417 {
418     HRESULT hr;
419     UINT cChars;
420     IShellFolder *psfDesktop, *psfChild, *psfMyComputer, *psfSystemDir;
421     SHITEMID emptyitem = { 0, { 0 } };
422     LPITEMIDLIST pidlMyComputer, pidlSystemDir, pidl, pidlEmpty = (LPITEMIDLIST)&emptyitem;
423     WCHAR wszSystemDir[MAX_PATH];
424     char szSystemDir[MAX_PATH];
425     char buf[MAX_PATH];
426     WCHAR path[MAX_PATH];
427     CHAR pathA[MAX_PATH];
428     HANDLE hfile;
429     WCHAR wszMyComputer[] = {
430         ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
431         'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
432     static const CHAR filename_html[] = "winetest.html";
433     static const CHAR filename_txt[] = "winetest.txt";
434     static const CHAR filename_foo[] = "winetest.foo";
435 
436     /* The following tests shows that BindToObject should fail with E_INVALIDARG if called
437      * with an empty pidl. This is tested for Desktop, MyComputer and the FS ShellFolder
438      */
439     hr = SHGetDesktopFolder(&psfDesktop);
440     ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
441     if (hr != S_OK) return;
442 
443     hr = IShellFolder_BindToObject(psfDesktop, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
444     ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
445 
446     hr = IShellFolder_BindToObject(psfDesktop, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
447     ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
448 
449     hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
450     ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
451     if (hr != S_OK) {
452         IShellFolder_Release(psfDesktop);
453         return;
454     }
455 
456     hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
457     ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
458     IShellFolder_Release(psfDesktop);
459     IMalloc_Free(ppM, pidlMyComputer);
460     if (hr != S_OK) return;
461 
462     hr = IShellFolder_BindToObject(psfMyComputer, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
463     ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
464 
465     hr = IShellFolder_BindToObject(psfMyComputer, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
466     ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
467 
468     cChars = GetSystemDirectoryA(szSystemDir, MAX_PATH);
469     ok (cChars > 0 && cChars < MAX_PATH, "GetSystemDirectoryA failed! LastError: %u\n", GetLastError());
470     if (cChars == 0 || cChars >= MAX_PATH) {
471         IShellFolder_Release(psfMyComputer);
472         return;
473     }
474     MultiByteToWideChar(CP_ACP, 0, szSystemDir, -1, wszSystemDir, MAX_PATH);
475 
476     hr = IShellFolder_ParseDisplayName(psfMyComputer, NULL, NULL, wszSystemDir, NULL, &pidlSystemDir, NULL);
477     ok (hr == S_OK, "MyComputers's ParseDisplayName failed to parse the SystemDirectory! hr = %08x\n", hr);
478     if (hr != S_OK) {
479         IShellFolder_Release(psfMyComputer);
480         return;
481     }
482 
483     hr = IShellFolder_BindToObject(psfMyComputer, pidlSystemDir, NULL, &IID_IShellFolder, (LPVOID*)&psfSystemDir);
484     ok (hr == S_OK, "MyComputer failed to bind to a FileSystem ShellFolder! hr = %08x\n", hr);
485     IShellFolder_Release(psfMyComputer);
486     IMalloc_Free(ppM, pidlSystemDir);
487     if (hr != S_OK) return;
488 
489     hr = IShellFolder_BindToObject(psfSystemDir, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
490     ok (hr == E_INVALIDARG,
491         "FileSystem ShellFolder's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
492 
493     hr = IShellFolder_BindToObject(psfSystemDir, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
494     ok (hr == E_INVALIDARG,
495         "FileSystem ShellFolder's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
496 
497     IShellFolder_Release(psfSystemDir);
498 
499     cChars = GetCurrentDirectoryA(MAX_PATH, buf);
500     if(!cChars)
501     {
502         skip("Failed to get current directory, skipping tests.\n");
503         return;
504     }
505     if(buf[cChars-1] != '\\') lstrcatA(buf, "\\");
506 
507     SHGetDesktopFolder(&psfDesktop);
508 
509     /* Attempt BindToObject on files. */
510 
511     /* .html */
512     lstrcpyA(pathA, buf);
513     lstrcatA(pathA, filename_html);
514     hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
515     if(hfile != INVALID_HANDLE_VALUE)
516     {
517         CloseHandle(hfile);
518         MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
519         hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
520         ok(hr == S_OK, "Got 0x%08x\n", hr);
521         if(SUCCEEDED(hr))
522         {
523             hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
524             ok(hr == S_OK ||
525                hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
526                "Got 0x%08x\n", hr);
527             if(SUCCEEDED(hr))
528             {
529                 IPersist *pp;
530                 hr = IShellFolder_QueryInterface(psfChild, &IID_IPersist, (void**)&pp);
531                 ok(hr == S_OK, "Got 0x%08x\n", hr);
532                 if(SUCCEEDED(hr))
533                 {
534                     CLSID id;
535                     hr = IPersist_GetClassID(pp, &id);
536                     ok(hr == S_OK, "Got 0x%08x\n", hr);
537                     ok(IsEqualIID(&id, &CLSID_ShellDocObjView), "Unexpected classid %s\n", wine_dbgstr_guid(&id));
538                     IPersist_Release(pp);
539                 }
540 
541                 IShellFolder_Release(psfChild);
542             }
543             ILFree(pidl);
544         }
545         DeleteFileA(pathA);
546     }
547     else
548         win_skip("Failed to create .html testfile.\n");
549 
550     /* .txt */
551     lstrcpyA(pathA, buf);
552     lstrcatA(pathA, filename_txt);
553     hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
554     if(hfile != INVALID_HANDLE_VALUE)
555     {
556         CloseHandle(hfile);
557         MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
558         hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
559         ok(hr == S_OK, "Got 0x%08x\n", hr);
560         if(SUCCEEDED(hr))
561         {
562             hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
563             ok(hr == E_FAIL || /* Vista+ */
564                hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
565                "Got 0x%08x\n", hr);
566             if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
567             ILFree(pidl);
568         }
569         DeleteFileA(pathA);
570     }
571     else
572         win_skip("Failed to create .txt testfile.\n");
573 
574     /* .foo */
575     lstrcpyA(pathA, buf);
576     lstrcatA(pathA, filename_foo);
577     hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
578     if(hfile != INVALID_HANDLE_VALUE)
579     {
580         CloseHandle(hfile);
581         MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
582         hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
583         ok(hr == S_OK, "Got 0x%08x\n", hr);
584         if(SUCCEEDED(hr))
585         {
586             hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
587             ok(hr == E_FAIL || /* Vista+ */
588                hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
589                "Got 0x%08x\n", hr);
590             if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
591             ILFree(pidl);
592         }
593         DeleteFileA(pathA);
594     }
595     else
596         win_skip("Failed to create .foo testfile.\n");
597 
598     /* And on the desktop */
599     SHGetSpecialFolderPathA(NULL, pathA, CSIDL_DESKTOP, FALSE);
600     lstrcatA(pathA, "\\");
601     lstrcatA(pathA, filename_html);
602     hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
603 
604     CloseHandle(hfile);
605     MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
606     hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
607     ok(hr == S_OK, "Got 0x%08x\n", hr);
608 
609     hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void **)&psfChild);
610     ok(hr == S_OK ||
611        hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
612        "Got 0x%08x\n", hr);
613     if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
614     ILFree(pidl);
615     if(!DeleteFileA(pathA))
616         trace("Failed to delete: %d\n", GetLastError());
617 
618     SHGetSpecialFolderPathA(NULL, pathA, CSIDL_DESKTOP, FALSE);
619     lstrcatA(pathA, "\\");
620     lstrcatA(pathA, filename_foo);
621     hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
622 
623     CloseHandle(hfile);
624     MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
625     hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
626     ok(hr == S_OK, "Got 0x%08x\n", hr);
627 
628     hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void **)&psfChild);
629     ok(hr == E_FAIL || /* Vista+ */
630        hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
631        "Got 0x%08x\n", hr);
632     if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
633     ILFree(pidl);
634     DeleteFileA(pathA);
635 
636     IShellFolder_Release(psfDesktop);
637 }
638 
test_GetDisplayName(void)639 static void test_GetDisplayName(void)
640 {
641     BOOL result;
642     HRESULT hr;
643     HANDLE hTestFile;
644     WCHAR wszTestFile[MAX_PATH], wszTestFile2[MAX_PATH];
645     char szTestFile[MAX_PATH], szTestDir[MAX_PATH];
646     DWORD attr;
647     STRRET strret;
648     LPSHELLFOLDER psfDesktop, psfPersonal;
649     IUnknown *psfFile;
650     SHITEMID emptyitem = { 0, { 0 } };
651     LPITEMIDLIST pidlTestFile, pidlEmpty = (LPITEMIDLIST)&emptyitem;
652     LPCITEMIDLIST pidlLast;
653     static const CHAR szFileName[] = "winetest.foo";
654     static const WCHAR wszFileName[] = { 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
655     static const WCHAR wszDirName[] = { 'w','i','n','e','t','e','s','t',0 };
656 
657     /* It's ok to use this fixed path. Call will fail anyway. */
658     WCHAR wszAbsoluteFilename[] = { 'C',':','\\','w','i','n','e','t','e','s','t', 0 };
659     LPITEMIDLIST pidlNew;
660 
661     /* I'm trying to figure if there is a functional difference between calling
662      * SHGetPathFromIDListW and calling GetDisplayNameOf(SHGDN_FORPARSING) after
663      * binding to the shellfolder. One thing I thought of was that perhaps
664      * SHGetPathFromIDListW would be able to get the path to a file, which does
665      * not exist anymore, while the other method wouldn't. It turns out there's
666      * no functional difference in this respect.
667      */
668 
669     /* First creating a directory in MyDocuments and a file in this directory. */
670     result = SHGetSpecialFolderPathA(NULL, szTestDir, CSIDL_PERSONAL, FALSE);
671     ok(result, "SHGetSpecialFolderPathA failed! Last error: %u\n", GetLastError());
672     if (!result) return;
673 
674     /* Use ANSI file functions so this works on Windows 9x */
675     lstrcatA(szTestDir, "\\winetest");
676     CreateDirectoryA(szTestDir, NULL);
677     attr=GetFileAttributesA(szTestDir);
678     if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY))
679     {
680         ok(0, "unable to create the '%s' directory\n", szTestDir);
681         return;
682     }
683 
684     lstrcpyA(szTestFile, szTestDir);
685     lstrcatA(szTestFile, "\\");
686     lstrcatA(szTestFile, szFileName);
687     hTestFile = CreateFileA(szTestFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
688     ok((hTestFile != INVALID_HANDLE_VALUE), "CreateFileA failed! Last error: %u\n", GetLastError());
689     if (hTestFile == INVALID_HANDLE_VALUE) return;
690     CloseHandle(hTestFile);
691 
692     /* Getting an itemidlist for the file. */
693     hr = SHGetDesktopFolder(&psfDesktop);
694     ok(hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
695     if (hr != S_OK) return;
696 
697     MultiByteToWideChar(CP_ACP, 0, szTestFile, -1, wszTestFile, MAX_PATH);
698 
699     hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
700     ok(hr == S_OK, "Desktop->ParseDisplayName failed! hr = %08x\n", hr);
701     if (hr != S_OK) {
702         IShellFolder_Release(psfDesktop);
703         return;
704     }
705 
706     pidlLast = ILFindLastID(pidlTestFile);
707     ok(pidlLast->mkid.cb >= 76, "Expected pidl length of at least 76, got %d.\n", pidlLast->mkid.cb);
708     if (pidlLast->mkid.cb >= 28) {
709         ok(!lstrcmpA((CHAR*)&pidlLast->mkid.abID[12], szFileName),
710             "Filename should be stored as ansi-string at this position!\n");
711     }
712     /* WinXP and up store the filenames as both ANSI and UNICODE in the pidls */
713     if (pidlLast->mkid.cb >= 76) {
714         ok(!lstrcmpW((WCHAR*)&pidlLast->mkid.abID[46], wszFileName) ||
715             (pidlLast->mkid.cb >= 94 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[64], wszFileName)) ||  /* Vista */
716             (pidlLast->mkid.cb >= 98 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[68], wszFileName)) ||  /* Win7 */
717             (pidlLast->mkid.cb >= 102 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[72], wszFileName)),   /* Win8 */
718             "Filename should be stored as wchar-string at this position!\n");
719     }
720 
721     /* It seems as if we cannot bind to regular files on windows, but only directories.
722      */
723     hr = IShellFolder_BindToObject(psfDesktop, pidlTestFile, NULL, &IID_IUnknown, (VOID**)&psfFile);
724     ok (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
725         hr == E_NOTIMPL, /* Vista */
726         "hr = %08x\n", hr);
727     if (hr == S_OK) {
728         IUnknown_Release(psfFile);
729     }
730 
731     /* Some tests for IShellFolder::SetNameOf */
732     hr = SHBindToParent(pidlTestFile, &IID_IShellFolder, (void **)&psfPersonal, &pidlLast);
733     ok(hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
734 
735     /* The pidl returned through the last parameter of SetNameOf is a simple one. */
736     hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlLast, wszDirName, SHGDN_NORMAL, &pidlNew);
737     ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
738 
739     ok (((ITEMIDLIST *)((BYTE *)pidlNew + pidlNew->mkid.cb))->mkid.cb == 0,
740         "pidl returned from SetNameOf should be simple!\n");
741 
742     /* Passing an absolute path to SetNameOf fails. The HRESULT code indicates that SetNameOf
743      * is implemented on top of SHFileOperation in WinXP. */
744     hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszAbsoluteFilename, SHGDN_FORPARSING, NULL);
745     ok (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED), "SetNameOf succeeded! hr = %08x\n", hr);
746 
747     /* Rename the file back to its original name. SetNameOf ignores the fact, that the
748      * SHGDN flags specify an absolute path. */
749     hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszFileName, SHGDN_FORPARSING, NULL);
750     ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
751 
752     ILFree(pidlNew);
753     IShellFolder_Release(psfPersonal);
754 
755     /* Deleting the file and the directory */
756     DeleteFileA(szTestFile);
757     RemoveDirectoryA(szTestDir);
758 
759     /* SHGetPathFromIDListW still works, although the file is not present anymore. */
760     result = SHGetPathFromIDListW(pidlTestFile, wszTestFile2);
761     ok (result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
762     ok (!lstrcmpiW(wszTestFile, wszTestFile2), "SHGetPathFromIDListW returns incorrect path!\n");
763 
764     /* SHBindToParent fails, if called with a NULL PIDL. */
765     hr = SHBindToParent(NULL, &IID_IShellFolder, (void **)&psfPersonal, &pidlLast);
766     ok (hr == E_INVALIDARG || broken(hr == E_OUTOFMEMORY) /* XP */,
767         "SHBindToParent(NULL) should fail! hr = %08x\n", hr);
768 
769     /* But it succeeds with an empty PIDL. */
770     hr = SHBindToParent(pidlEmpty, &IID_IShellFolder, (void **)&psfPersonal, &pidlLast);
771     ok (hr == S_OK, "SHBindToParent(empty PIDL) should succeed! hr = %08x\n", hr);
772     ok (pidlLast == pidlEmpty, "The last element of an empty PIDL should be the PIDL itself!\n");
773     if (hr == S_OK)
774         IShellFolder_Release(psfPersonal);
775 
776     /* Binding to the folder and querying the display name of the file also works. */
777     hr = SHBindToParent(pidlTestFile, &IID_IShellFolder, (void **)&psfPersonal, &pidlLast);
778     ok (hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
779     if (hr != S_OK) {
780         IShellFolder_Release(psfDesktop);
781         return;
782     }
783 
784     /* This test shows that Windows doesn't allocate a new pidlLast, but returns a pointer into
785      * pidlTestFile (In accordance with MSDN). */
786     ok (ILFindLastID(pidlTestFile) == pidlLast,
787                                 "SHBindToParent doesn't return the last id of the pidl param!\n");
788 
789     hr = IShellFolder_GetDisplayNameOf(psfPersonal, pidlLast, SHGDN_FORPARSING, &strret);
790     ok (hr == S_OK, "Personal->GetDisplayNameOf failed! hr = %08x\n", hr);
791     if (hr != S_OK) {
792         IShellFolder_Release(psfDesktop);
793         IShellFolder_Release(psfPersonal);
794         return;
795     }
796 
797     hr = StrRetToBufW(&strret, pidlLast, wszTestFile2, MAX_PATH);
798     ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
799     ok (!lstrcmpiW(wszTestFile, wszTestFile2), "GetDisplayNameOf returns incorrect path!\n");
800 
801     ILFree(pidlTestFile);
802     IShellFolder_Release(psfDesktop);
803     IShellFolder_Release(psfPersonal);
804 }
805 
test_CallForAttributes(void)806 static void test_CallForAttributes(void)
807 {
808     HKEY hKey;
809     LONG lResult;
810     HRESULT hr;
811     DWORD dwSize;
812     LPSHELLFOLDER psfDesktop;
813     LPITEMIDLIST pidlMyDocuments;
814     DWORD dwAttributes, dwCallForAttributes, dwOrigAttributes, dwOrigCallForAttributes;
815     static const WCHAR wszAttributes[] = { 'A','t','t','r','i','b','u','t','e','s',0 };
816     static const WCHAR wszCallForAttributes[] = {
817         'C','a','l','l','F','o','r','A','t','t','r','i','b','u','t','e','s',0 };
818     static const WCHAR wszMyDocumentsKey[] = {
819         'C','L','S','I','D','\\','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-',
820         '1','1','D','0','-','9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',
821         '\\','S','h','e','l','l','F','o','l','d','e','r',0 };
822     WCHAR wszMyDocuments[] = {
823         ':',':','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-','1','1','D','0','-',
824         '9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',0 };
825 
826     /* For the root of a namespace extension, the attributes are not queried by binding
827      * to the object and calling GetAttributesOf. Instead, the attributes are read from
828      * the registry value HKCR/CLSID/{...}/ShellFolder/Attributes. This is documented on MSDN.
829      *
830      * The MyDocuments shellfolder on WinXP has a HKCR/CLSID/{...}/ShellFolder/CallForAttributes
831      * value. It seems that if the folder is queried for one of the flags set in CallForAttributes,
832      * the shell does bind to the folder object and calls GetAttributesOf. This is not documented
833      * on MSDN. This test is meant to document the observed behaviour on WinXP SP2.
834      */
835     hr = SHGetDesktopFolder(&psfDesktop);
836     ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
837     if (hr != S_OK) return;
838 
839     hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyDocuments, NULL,
840                                        &pidlMyDocuments, NULL);
841     ok (hr == S_OK,
842         "Desktop's ParseDisplayName failed to parse MyDocuments's CLSID! hr = %08x\n", hr);
843     if (hr != S_OK) {
844         IShellFolder_Release(psfDesktop);
845         return;
846     }
847 
848     dwAttributes = 0xffffffff;
849     hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
850                                       (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
851     ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
852 
853     /* We need the following setup (as observed on WinXP SP2), for the tests to make sense. */
854     ok (dwAttributes & SFGAO_FILESYSTEM, "SFGAO_FILESYSTEM attribute is not set for MyDocuments!\n");
855     ok (!(dwAttributes & SFGAO_ISSLOW), "SFGAO_ISSLOW attribute is set for MyDocuments!\n");
856     ok (!(dwAttributes & SFGAO_GHOSTED), "SFGAO_GHOSTED attribute is set for MyDocuments!\n");
857 
858     /* We don't have the MyDocuments shellfolder in wine yet, and thus we don't have the registry
859      * key. So the test will return at this point, if run on wine.
860      */
861     lResult = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszMyDocumentsKey, 0, KEY_WRITE|KEY_READ, &hKey);
862     ok (lResult == ERROR_SUCCESS ||
863         lResult == ERROR_ACCESS_DENIED,
864         "RegOpenKeyEx failed! result: %08x\n", lResult);
865     if (lResult != ERROR_SUCCESS) {
866         if (lResult == ERROR_ACCESS_DENIED)
867             skip("Not enough rights to open the registry key\n");
868         IMalloc_Free(ppM, pidlMyDocuments);
869         IShellFolder_Release(psfDesktop);
870         return;
871     }
872 
873     /* Query MyDocuments' Attributes value, to be able to restore it later. */
874     dwSize = sizeof(DWORD);
875     lResult = RegQueryValueExW(hKey, wszAttributes, NULL, NULL, (LPBYTE)&dwOrigAttributes, &dwSize);
876     ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
877     if (lResult != ERROR_SUCCESS) {
878         RegCloseKey(hKey);
879         IMalloc_Free(ppM, pidlMyDocuments);
880         IShellFolder_Release(psfDesktop);
881         return;
882     }
883 
884     /* Query MyDocuments' CallForAttributes value, to be able to restore it later. */
885     dwSize = sizeof(DWORD);
886     lResult = RegQueryValueExW(hKey, wszCallForAttributes, NULL, NULL,
887                               (LPBYTE)&dwOrigCallForAttributes, &dwSize);
888     ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
889     if (lResult != ERROR_SUCCESS) {
890         RegCloseKey(hKey);
891         IMalloc_Free(ppM, pidlMyDocuments);
892         IShellFolder_Release(psfDesktop);
893         return;
894     }
895 
896     /* Define via the Attributes value that MyDocuments attributes are SFGAO_ISSLOW and
897      * SFGAO_GHOSTED and that MyDocuments should be called for the SFGAO_ISSLOW and
898      * SFGAO_FILESYSTEM attributes. */
899     dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED;
900     RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwAttributes, sizeof(DWORD));
901     dwCallForAttributes = SFGAO_ISSLOW|SFGAO_FILESYSTEM;
902     RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
903                    (LPBYTE)&dwCallForAttributes, sizeof(DWORD));
904 
905     /* Although it is not set in CallForAttributes, the SFGAO_GHOSTED flag is reset by
906      * GetAttributesOf. It seems that once there is a single attribute queried, for which
907      * CallForAttributes is set, all flags are taken from the GetAttributesOf call and
908      * the flags in Attributes are ignored.
909      */
910     dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED|SFGAO_FILESYSTEM;
911     hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
912                                       (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
913     ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
914     if (hr == S_OK)
915         ok (dwAttributes == SFGAO_FILESYSTEM,
916             "Desktop->GetAttributes(MyDocuments) returned unexpected attributes: %08x\n",
917             dwAttributes);
918 
919     /* Restore MyDocuments' original Attributes and CallForAttributes registry values */
920     RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwOrigAttributes, sizeof(DWORD));
921     RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
922                    (LPBYTE)&dwOrigCallForAttributes, sizeof(DWORD));
923     RegCloseKey(hKey);
924     IMalloc_Free(ppM, pidlMyDocuments);
925     IShellFolder_Release(psfDesktop);
926 }
927 
test_GetAttributesOf(void)928 static void test_GetAttributesOf(void)
929 {
930     HRESULT hr;
931     LPSHELLFOLDER psfDesktop, psfMyComputer;
932     SHITEMID emptyitem = { 0, { 0 } };
933     LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
934     LPITEMIDLIST pidlMyComputer;
935     DWORD dwFlags;
936     static const DWORD desktopFlags = SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR |
937         SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER;
938     static const DWORD myComputerFlags = SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET |
939         SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
940     WCHAR wszMyComputer[] = {
941         ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
942         'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
943     char  cCurrDirA [MAX_PATH] = {0};
944     WCHAR cCurrDirW [MAX_PATH];
945     static WCHAR cTestDirW[] = {'t','e','s','t','d','i','r',0};
946     IShellFolder *IDesktopFolder, *testIShellFolder;
947     ITEMIDLIST *newPIDL;
948     int len;
949 
950     hr = SHGetDesktopFolder(&psfDesktop);
951     ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
952     if (hr != S_OK) return;
953 
954     /* The Desktop attributes can be queried with a single empty itemidlist, .. */
955     dwFlags = 0xffffffff;
956     hr = IShellFolder_GetAttributesOf(psfDesktop, 1, &pidlEmpty, &dwFlags);
957     ok (hr == S_OK, "Desktop->GetAttributesOf(empty pidl) failed! hr = %08x\n", hr);
958     ok (dwFlags == desktopFlags, "Wrong Desktop attributes: %08x\n", dwFlags);
959 
960     /* .. or with no itemidlist at all. */
961     dwFlags = 0xffffffff;
962     hr = IShellFolder_GetAttributesOf(psfDesktop, 0, NULL, &dwFlags);
963     ok (hr == S_OK, "Desktop->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
964     ok (dwFlags == desktopFlags, "Wrong Desktop attributes: %08x\n", dwFlags);
965 
966     /* Testing the attributes of the MyComputer shellfolder */
967     hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
968     ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
969     if (hr != S_OK) {
970         IShellFolder_Release(psfDesktop);
971         return;
972     }
973 
974     /* Windows sets the SFGAO_CANLINK flag, when MyComputer is queried via the Desktop
975      * folder object. It doesn't do this, if MyComputer is queried directly (see below).
976      */
977     dwFlags = 0xffffffff;
978     hr = IShellFolder_GetAttributesOf(psfDesktop, 1, (LPCITEMIDLIST*)&pidlMyComputer, &dwFlags);
979     ok (hr == S_OK, "Desktop->GetAttributesOf(MyComputer) failed! hr = %08x\n", hr);
980     todo_wine
981     ok (dwFlags == (myComputerFlags | SFGAO_CANLINK), "Wrong MyComputer attributes: %08x\n", dwFlags);
982 
983     hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
984     ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
985     IShellFolder_Release(psfDesktop);
986     IMalloc_Free(ppM, pidlMyComputer);
987     if (hr != S_OK) return;
988 
989     hr = IShellFolder_GetAttributesOf(psfMyComputer, 1, &pidlEmpty, &dwFlags);
990     todo_wine
991     ok (hr == E_INVALIDARG, "MyComputer->GetAttributesOf(empty pidl) should fail! hr = %08x\n", hr);
992 
993     dwFlags = 0xffffffff;
994     hr = IShellFolder_GetAttributesOf(psfMyComputer, 0, NULL, &dwFlags);
995     ok (hr == S_OK, "MyComputer->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
996     todo_wine
997     ok (dwFlags == myComputerFlags, "Wrong MyComputer attributes: %08x\n", dwFlags);
998 
999     IShellFolder_Release(psfMyComputer);
1000 
1001     GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1002     len = lstrlenA(cCurrDirA);
1003 
1004     if (len == 0) {
1005         win_skip("GetCurrentDirectoryA returned empty string. Skipping test_GetAttributesOf\n");
1006         return;
1007     }
1008     if (len > 3 && cCurrDirA[len-1] == '\\')
1009         cCurrDirA[len-1] = 0;
1010 
1011     /* create test directory */
1012     CreateFilesFolders();
1013 
1014     MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1015 
1016     hr = SHGetDesktopFolder(&IDesktopFolder);
1017     ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1018 
1019     hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1020     ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1021 
1022     hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1023     ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1024 
1025     IMalloc_Free(ppM, newPIDL);
1026 
1027     /* get relative PIDL */
1028     hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1029     ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1030 
1031     /* test the shell attributes of the test directory using the relative PIDL */
1032     dwFlags = SFGAO_FOLDER;
1033     hr = IShellFolder_GetAttributesOf(testIShellFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
1034     ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
1035     ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for relative PIDL: %08x\n", dwFlags);
1036 
1037     /* free memory */
1038     IMalloc_Free(ppM, newPIDL);
1039 
1040     /* append testdirectory name to path */
1041     if (cCurrDirA[len-1] == '\\')
1042         cCurrDirA[len-1] = 0;
1043     lstrcatA(cCurrDirA, "\\testdir");
1044     MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1045 
1046     hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1047     ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1048 
1049     /* test the shell attributes of the test directory using the absolute PIDL */
1050     dwFlags = SFGAO_FOLDER;
1051     hr = IShellFolder_GetAttributesOf(IDesktopFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
1052     ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
1053     ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for absolute PIDL: %08x\n", dwFlags);
1054 
1055     /* free memory */
1056     IMalloc_Free(ppM, newPIDL);
1057 
1058     IShellFolder_Release(testIShellFolder);
1059 
1060     Cleanup();
1061 
1062     IShellFolder_Release(IDesktopFolder);
1063 }
1064 
test_SHGetPathFromIDList(void)1065 static void test_SHGetPathFromIDList(void)
1066 {
1067     SHITEMID emptyitem = { 0, { 0 } };
1068     LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
1069     LPITEMIDLIST pidlMyComputer;
1070     WCHAR wszPath[MAX_PATH], wszDesktop[MAX_PATH];
1071     BOOL result;
1072     HRESULT hr;
1073     LPSHELLFOLDER psfDesktop;
1074     WCHAR wszMyComputer[] = {
1075         ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
1076         'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
1077     WCHAR wszFileName[MAX_PATH];
1078     LPITEMIDLIST pidlTestFile;
1079     HANDLE hTestFile;
1080     STRRET strret;
1081     static WCHAR wszTestFile[] = {
1082         'w','i','n','e','t','e','s','t','.','f','o','o',0 };
1083     LPITEMIDLIST pidlPrograms;
1084 
1085     /* Calling SHGetPathFromIDListW with no pidl should return the empty string */
1086     wszPath[0] = 'a';
1087     wszPath[1] = '\0';
1088     result = SHGetPathFromIDListW(NULL, wszPath);
1089     ok(!result, "Expected failure\n");
1090     ok(!wszPath[0], "Expected empty string\n");
1091 
1092     /* Calling SHGetPathFromIDListW with an empty pidl should return the desktop folder's path. */
1093     result = SHGetSpecialFolderPathW(NULL, wszDesktop, CSIDL_DESKTOP, FALSE);
1094     ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOP) failed! Last error: %u\n", GetLastError());
1095     if (!result) return;
1096 
1097     result = SHGetPathFromIDListW(pidlEmpty, wszPath);
1098     ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1099     if (!result) return;
1100     ok(!lstrcmpiW(wszDesktop, wszPath), "SHGetPathFromIDListW didn't return desktop path for empty pidl!\n");
1101 
1102     /* MyComputer does not map to a filesystem path. SHGetPathFromIDListW should fail. */
1103     hr = SHGetDesktopFolder(&psfDesktop);
1104     ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1105     if (hr != S_OK) return;
1106 
1107     hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1108     ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1109     if (hr != S_OK) {
1110         IShellFolder_Release(psfDesktop);
1111         return;
1112     }
1113 
1114     SetLastError(0xdeadbeef);
1115     wszPath[0] = 'a';
1116     wszPath[1] = '\0';
1117     result = SHGetPathFromIDListW(pidlMyComputer, wszPath);
1118     ok (!result, "SHGetPathFromIDListW succeeded where it shouldn't!\n");
1119     ok (GetLastError()==0xdeadbeef ||
1120         GetLastError()==ERROR_SUCCESS, /* Vista and higher */
1121         "Unexpected last error from SHGetPathFromIDListW: %u\n", GetLastError());
1122     ok (!wszPath[0], "Expected empty path\n");
1123     if (result) {
1124         IShellFolder_Release(psfDesktop);
1125         return;
1126     }
1127 
1128     IMalloc_Free(ppM, pidlMyComputer);
1129 
1130     result = SHGetSpecialFolderPathW(NULL, wszFileName, CSIDL_DESKTOPDIRECTORY, FALSE);
1131     ok(result, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1132     if (!result) {
1133         IShellFolder_Release(psfDesktop);
1134         return;
1135     }
1136     myPathAddBackslashW(wszFileName);
1137     lstrcatW(wszFileName, wszTestFile);
1138     hTestFile = CreateFileW(wszFileName, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
1139     ok(hTestFile != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: %u\n", GetLastError());
1140     if (hTestFile == INVALID_HANDLE_VALUE) {
1141         IShellFolder_Release(psfDesktop);
1142         return;
1143     }
1144     CloseHandle(hTestFile);
1145 
1146     hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
1147     ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse filename hr = %08x\n", hr);
1148     if (hr != S_OK) {
1149         IShellFolder_Release(psfDesktop);
1150         DeleteFileW(wszFileName);
1151         IMalloc_Free(ppM, pidlTestFile);
1152         return;
1153     }
1154 
1155     /* This test is to show that the Desktop shellfolder prepends the CSIDL_DESKTOPDIRECTORY
1156      * path for files placed on the desktop, if called with SHGDN_FORPARSING. */
1157     hr = IShellFolder_GetDisplayNameOf(psfDesktop, pidlTestFile, SHGDN_FORPARSING, &strret);
1158     ok (hr == S_OK, "Desktop's GetDisplayNamfOf failed! hr = %08x\n", hr);
1159     IShellFolder_Release(psfDesktop);
1160     DeleteFileW(wszFileName);
1161     if (hr != S_OK) {
1162         IMalloc_Free(ppM, pidlTestFile);
1163         return;
1164     }
1165     StrRetToBufW(&strret, pidlTestFile, wszPath, MAX_PATH);
1166     ok(0 == lstrcmpW(wszFileName, wszPath),
1167        "Desktop->GetDisplayNameOf(pidlTestFile, SHGDN_FORPARSING) "
1168        "returned incorrect path for file placed on desktop\n");
1169 
1170     result = SHGetPathFromIDListW(pidlTestFile, wszPath);
1171     ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1172     ok(0 == lstrcmpW(wszFileName, wszPath), "SHGetPathFromIDListW returned incorrect path for file placed on desktop\n");
1173 
1174     if (pSHGetPathFromIDListEx)
1175     {
1176         result = pSHGetPathFromIDListEx(pidlEmpty, wszPath, MAX_PATH, SFGAO_FILESYSTEM);
1177         ok(result, "SHGetPathFromIDListEx failed: %u\n", GetLastError());
1178         ok(!lstrcmpiW(wszDesktop, wszPath), "Unexpected SHGetPathFromIDListEx result %s, expected %s\n",
1179            wine_dbgstr_w(wszPath), wine_dbgstr_w(wszDesktop));
1180 
1181         result = pSHGetPathFromIDListEx(pidlTestFile, wszPath, MAX_PATH, SFGAO_FILESYSTEM);
1182         ok(result, "SHGetPathFromIDListEx failed: %u\n", GetLastError());
1183         ok(!lstrcmpiW(wszFileName, wszPath), "Unexpected SHGetPathFromIDListEx result %s, expected %s\n",
1184            wine_dbgstr_w(wszPath), wine_dbgstr_w(wszFileName));
1185 
1186         SetLastError(0xdeadbeef);
1187         memset(wszPath, 0x55, sizeof(wszPath));
1188         result = pSHGetPathFromIDListEx(pidlTestFile, wszPath, 5, SFGAO_FILESYSTEM);
1189         ok(!result, "SHGetPathFromIDListEx returned: %x(%u)\n", result, GetLastError());
1190 
1191         SetLastError(0xdeadbeef);
1192         memset(wszPath, 0x55, sizeof(wszPath));
1193         result = pSHGetPathFromIDListEx(pidlEmpty, wszPath, 5, SFGAO_FILESYSTEM);
1194         ok(!result, "SHGetPathFromIDListEx returned: %x(%u)\n", result, GetLastError());
1195     }
1196     else
1197         win_skip("SHGetPathFromIDListEx not available\n");
1198 
1199     IMalloc_Free(ppM, pidlTestFile);
1200 
1201     /* Test if we can get the path from the start menu "program files" PIDL. */
1202     hr = SHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidlPrograms);
1203     ok(hr == S_OK, "SHGetFolderLocation failed: 0x%08x\n", hr);
1204 
1205     SetLastError(0xdeadbeef);
1206     result = SHGetPathFromIDListW(pidlPrograms, wszPath);
1207     IMalloc_Free(ppM, pidlPrograms);
1208     ok(result, "SHGetPathFromIDListW failed\n");
1209 }
1210 
test_EnumObjects_and_CompareIDs(void)1211 static void test_EnumObjects_and_CompareIDs(void)
1212 {
1213     ITEMIDLIST *newPIDL;
1214     IShellFolder *IDesktopFolder, *testIShellFolder;
1215     char  cCurrDirA [MAX_PATH] = {0};
1216     static const CHAR cTestDirA[] = "\\testdir";
1217     WCHAR cTestDirW[MAX_PATH];
1218     int len;
1219     HRESULT hr;
1220 
1221     GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1222     len = lstrlenA(cCurrDirA);
1223 
1224     if(len == 0) {
1225         win_skip("GetCurrentDirectoryA returned empty string. Skipping test_EnumObjects_and_CompareIDs\n");
1226         return;
1227     }
1228     if(cCurrDirA[len-1] == '\\')
1229         cCurrDirA[len-1] = 0;
1230 
1231     lstrcatA(cCurrDirA, cTestDirA);
1232     MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cTestDirW, MAX_PATH);
1233 
1234     hr = SHGetDesktopFolder(&IDesktopFolder);
1235     ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1236 
1237     CreateFilesFolders();
1238 
1239     hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1240     ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1241 
1242     hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1243     ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1244 
1245     test_EnumObjects(testIShellFolder);
1246 
1247     IShellFolder_Release(testIShellFolder);
1248 
1249     Cleanup();
1250 
1251     IMalloc_Free(ppM, newPIDL);
1252 
1253     IShellFolder_Release(IDesktopFolder);
1254 }
1255 
1256 /* A simple implementation of an IPropertyBag, which returns fixed values for
1257  * 'Target' and 'Attributes' properties.
1258  */
InitPropertyBag_IPropertyBag_QueryInterface(IPropertyBag * iface,REFIID riid,void ** ppvObject)1259 static HRESULT WINAPI InitPropertyBag_IPropertyBag_QueryInterface(IPropertyBag *iface, REFIID riid,
1260     void **ppvObject)
1261 {
1262     if (!ppvObject)
1263         return E_INVALIDARG;
1264 
1265     if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPropertyBag, riid)) {
1266         *ppvObject = iface;
1267     } else {
1268         ok (FALSE, "InitPropertyBag asked for unknown interface!\n");
1269         return E_NOINTERFACE;
1270     }
1271 
1272     IPropertyBag_AddRef(iface);
1273     return S_OK;
1274 }
1275 
InitPropertyBag_IPropertyBag_AddRef(IPropertyBag * iface)1276 static ULONG WINAPI InitPropertyBag_IPropertyBag_AddRef(IPropertyBag *iface) {
1277     return 2;
1278 }
1279 
InitPropertyBag_IPropertyBag_Release(IPropertyBag * iface)1280 static ULONG WINAPI InitPropertyBag_IPropertyBag_Release(IPropertyBag *iface) {
1281     return 1;
1282 }
1283 
InitPropertyBag_IPropertyBag_Read(IPropertyBag * iface,LPCOLESTR pszPropName,VARIANT * pVar,IErrorLog * pErrorLog)1284 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Read(IPropertyBag *iface, LPCOLESTR pszPropName,
1285     VARIANT *pVar, IErrorLog *pErrorLog)
1286 {
1287     static const WCHAR wszTargetSpecialFolder[] = {
1288         'T','a','r','g','e','t','S','p','e','c','i','a','l','F','o','l','d','e','r',0 };
1289     static const WCHAR wszTarget[] = {
1290         'T','a','r','g','e','t',0 };
1291     static const WCHAR wszAttributes[] = {
1292         'A','t','t','r','i','b','u','t','e','s',0 };
1293     static const WCHAR wszResolveLinkFlags[] = {
1294         'R','e','s','o','l','v','e','L','i','n','k','F','l','a','g','s',0 };
1295     static const WCHAR wszTargetKnownFolder[] = {
1296         'T','a','r','g','e','t','K','n','o','w','n','F','o','l','d','e','r',0 };
1297     static const WCHAR wszCLSID[] = {
1298         'C','L','S','I','D',0 };
1299 
1300     if (!lstrcmpW(pszPropName, wszTargetSpecialFolder)) {
1301         ok(V_VT(pVar) == VT_I4, "Wrong variant type for 'TargetSpecialFolder' property!\n");
1302         return E_INVALIDARG;
1303     }
1304 
1305     if (!lstrcmpW(pszPropName, wszResolveLinkFlags))
1306     {
1307         ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'ResolveLinkFlags' property!\n");
1308         return E_INVALIDARG;
1309     }
1310 
1311     if (!lstrcmpW(pszPropName, wszTarget)) {
1312         WCHAR wszPath[MAX_PATH];
1313         BOOL result;
1314 
1315         ok(V_VT(pVar) == VT_BSTR, "Wrong variant type for 'Target' property!\n");
1316         if (V_VT(pVar) != VT_BSTR) return E_INVALIDARG;
1317 
1318         result = SHGetSpecialFolderPathW(NULL, wszPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1319         ok(result, "SHGetSpecialFolderPathW(DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1320         if (!result) return E_INVALIDARG;
1321 
1322         V_BSTR(pVar) = SysAllocString(wszPath);
1323         return S_OK;
1324     }
1325 
1326     if (!lstrcmpW(pszPropName, wszAttributes)) {
1327         ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'Attributes' property!\n");
1328         if (V_VT(pVar) != VT_UI4) return E_INVALIDARG;
1329         V_UI4(pVar) = SFGAO_FOLDER|SFGAO_HASSUBFOLDER|SFGAO_FILESYSANCESTOR|
1330                       SFGAO_CANRENAME|SFGAO_FILESYSTEM;
1331         return S_OK;
1332     }
1333 
1334     if (!lstrcmpW(pszPropName, wszTargetKnownFolder)) {
1335         ok(V_VT(pVar) == VT_BSTR, "Wrong variant type for 'TargetKnownFolder' property!\n");
1336         /* TODO */
1337         return E_INVALIDARG;
1338     }
1339 
1340     if (!lstrcmpW(pszPropName, wszCLSID)) {
1341         ok(V_VT(pVar) == VT_EMPTY, "Wrong variant type for 'CLSID' property!\n");
1342         /* TODO */
1343         return E_INVALIDARG;
1344     }
1345 
1346     ok(FALSE, "PropertyBag was asked for unknown property %s (vt=%d)!\n", wine_dbgstr_w(pszPropName), V_VT(pVar));
1347     return E_INVALIDARG;
1348 }
1349 
InitPropertyBag_IPropertyBag_Write(IPropertyBag * iface,LPCOLESTR pszPropName,VARIANT * pVar)1350 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Write(IPropertyBag *iface, LPCOLESTR pszPropName,
1351     VARIANT *pVar)
1352 {
1353     ok(FALSE, "Unexpected call to IPropertyBag_Write\n");
1354     return E_NOTIMPL;
1355 }
1356 
1357 static const IPropertyBagVtbl InitPropertyBag_IPropertyBagVtbl = {
1358     InitPropertyBag_IPropertyBag_QueryInterface,
1359     InitPropertyBag_IPropertyBag_AddRef,
1360     InitPropertyBag_IPropertyBag_Release,
1361     InitPropertyBag_IPropertyBag_Read,
1362     InitPropertyBag_IPropertyBag_Write
1363 };
1364 
1365 static struct IPropertyBag InitPropertyBag = {
1366     &InitPropertyBag_IPropertyBagVtbl
1367 };
1368 
test_FolderShortcut(void)1369 static void test_FolderShortcut(void) {
1370     IPersistPropertyBag *pPersistPropertyBag;
1371     IShellFolder *pShellFolder, *pDesktopFolder;
1372     IPersistFolder3 *pPersistFolder3;
1373     HRESULT hr;
1374     STRRET strret;
1375     WCHAR wszDesktopPath[MAX_PATH], wszBuffer[MAX_PATH];
1376     BOOL result;
1377     CLSID clsid;
1378     LPITEMIDLIST pidlCurrentFolder, pidlWineTestFolder, pidlSubFolder;
1379     HKEY hShellExtKey;
1380     WCHAR wszWineTestFolder[] = {
1381         ':',':','{','9','B','3','5','2','E','B','F','-','2','7','6','5','-','4','5','C','1','-',
1382         'B','4','C','6','-','8','5','C','C','7','F','7','A','B','C','6','4','}',0 };
1383     WCHAR wszShellExtKey[] = { 'S','o','f','t','w','a','r','e','\\',
1384         'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
1385         'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1386         'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
1387         'N','a','m','e','S','p','a','c','e','\\',
1388         '{','9','b','3','5','2','e','b','f','-','2','7','6','5','-','4','5','c','1','-',
1389         'b','4','c','6','-','8','5','c','c','7','f','7','a','b','c','6','4','}',0 };
1390 
1391     WCHAR wszSomeSubFolder[] = { 'S','u','b','F','o','l','d','e','r', 0};
1392     static const GUID CLSID_UnixDosFolder =
1393         {0x9d20aae8, 0x0625, 0x44b0, {0x9c, 0xa7, 0x71, 0x88, 0x9c, 0x22, 0x54, 0xd9}};
1394 
1395     /* These tests basically show, that CLSID_FolderShortcuts are initialized
1396      * via their IPersistPropertyBag interface. And that the target folder
1397      * is taken from the IPropertyBag's 'Target' property.
1398      */
1399     hr = CoCreateInstance(&CLSID_FolderShortcut, NULL, CLSCTX_INPROC_SERVER,
1400                           &IID_IPersistPropertyBag, (LPVOID*)&pPersistPropertyBag);
1401     if (hr == REGDB_E_CLASSNOTREG) {
1402         win_skip("CLSID_FolderShortcut is not implemented\n");
1403         return;
1404     }
1405     ok (hr == S_OK, "CoCreateInstance failed! hr = 0x%08x\n", hr);
1406     if (hr != S_OK) return;
1407 
1408     hr = IPersistPropertyBag_Load(pPersistPropertyBag, &InitPropertyBag, NULL);
1409     ok(hr == S_OK, "IPersistPropertyBag_Load failed! hr = %08x\n", hr);
1410     if (hr != S_OK) {
1411         IPersistPropertyBag_Release(pPersistPropertyBag);
1412         return;
1413     }
1414 
1415     hr = IPersistPropertyBag_QueryInterface(pPersistPropertyBag, &IID_IShellFolder,
1416                                             (LPVOID*)&pShellFolder);
1417     IPersistPropertyBag_Release(pPersistPropertyBag);
1418     ok(hr == S_OK, "IPersistPropertyBag_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1419     if (hr != S_OK) return;
1420 
1421     hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1422     ok(hr == S_OK || broken(hr == E_INVALIDARG) /* win10 */,
1423        "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1424     if (hr != S_OK) {
1425         IShellFolder_Release(pShellFolder);
1426         return;
1427     }
1428 
1429     result = SHGetSpecialFolderPathW(NULL, wszDesktopPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1430     ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1431     if (!result) return;
1432 
1433     StrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1434     ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1435 
1436     hr = IShellFolder_QueryInterface(pShellFolder, &IID_IPersistFolder3, (LPVOID*)&pPersistFolder3);
1437     IShellFolder_Release(pShellFolder);
1438     ok(hr == S_OK, "IShellFolder_QueryInterface(IID_IPersistFolder3 failed! hr = 0x%08x\n", hr);
1439     if (hr != S_OK) return;
1440 
1441     hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1442     ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1443     ok(IsEqualCLSID(&clsid, &CLSID_FolderShortcut), "Unexpected CLSID!\n");
1444 
1445     hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1446     todo_wine ok(hr == S_FALSE, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1447     ok(!pidlCurrentFolder, "IPersistFolder3_GetCurFolder should return a NULL pidl!\n");
1448 
1449     /* For FolderShortcut objects, the Initialize method initialized the folder's position in the
1450      * shell namespace. The target folder, read from the property bag above, remains untouched.
1451      * The following tests show this: The itemidlist for some imaginary shellfolder object
1452      * is created and the FolderShortcut is initialized with it. GetCurFolder now returns this
1453      * itemidlist, but GetDisplayNameOf still returns the path from above.
1454      */
1455     hr = SHGetDesktopFolder(&pDesktopFolder);
1456     ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1457     if (hr != S_OK) return;
1458 
1459     /* Temporarily register WineTestFolder as a shell namespace extension at the Desktop.
1460      * Otherwise ParseDisplayName fails on WinXP with E_INVALIDARG */
1461     RegCreateKeyW(HKEY_CURRENT_USER, wszShellExtKey, &hShellExtKey);
1462     RegCloseKey(hShellExtKey);
1463     hr = IShellFolder_ParseDisplayName(pDesktopFolder, NULL, NULL, wszWineTestFolder, NULL,
1464                                        &pidlWineTestFolder, NULL);
1465     RegDeleteKeyW(HKEY_CURRENT_USER, wszShellExtKey);
1466     IShellFolder_Release(pDesktopFolder);
1467     ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1468     if (hr != S_OK) return;
1469 
1470     hr = IPersistFolder3_Initialize(pPersistFolder3, pidlWineTestFolder);
1471     ok (hr == S_OK, "IPersistFolder3::Initialize failed! hr = %08x\n", hr);
1472     if (hr != S_OK) {
1473         IPersistFolder3_Release(pPersistFolder3);
1474         ILFree(pidlWineTestFolder);
1475         return;
1476     }
1477 
1478     hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1479     ok(hr == S_OK, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1480     ok(ILIsEqual(pidlCurrentFolder, pidlWineTestFolder),
1481         "IPersistFolder3_GetCurFolder should return pidlWineTestFolder!\n");
1482     ILFree(pidlCurrentFolder);
1483     ILFree(pidlWineTestFolder);
1484 
1485     hr = IPersistFolder3_QueryInterface(pPersistFolder3, &IID_IShellFolder, (LPVOID*)&pShellFolder);
1486     IPersistFolder3_Release(pPersistFolder3);
1487     ok(hr == S_OK, "IPersistFolder3_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1488     if (hr != S_OK) return;
1489 
1490     hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1491     ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1492     if (hr != S_OK) {
1493         IShellFolder_Release(pShellFolder);
1494         return;
1495     }
1496 
1497     StrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1498     ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1499 
1500     /* Next few lines are meant to show that children of FolderShortcuts are not FolderShortcuts,
1501      * but ShellFSFolders. */
1502     myPathAddBackslashW(wszDesktopPath);
1503     lstrcatW(wszDesktopPath, wszSomeSubFolder);
1504     if (!CreateDirectoryW(wszDesktopPath, NULL)) {
1505         IShellFolder_Release(pShellFolder);
1506         return;
1507     }
1508 
1509     hr = IShellFolder_ParseDisplayName(pShellFolder, NULL, NULL, wszSomeSubFolder, NULL,
1510                                        &pidlSubFolder, NULL);
1511     RemoveDirectoryW(wszDesktopPath);
1512     ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1513     if (hr != S_OK) {
1514         IShellFolder_Release(pShellFolder);
1515         return;
1516     }
1517 
1518     hr = IShellFolder_BindToObject(pShellFolder, pidlSubFolder, NULL, &IID_IPersistFolder3,
1519                                    (LPVOID*)&pPersistFolder3);
1520     IShellFolder_Release(pShellFolder);
1521     ILFree(pidlSubFolder);
1522     ok (hr == S_OK, "IShellFolder::BindToObject failed! hr = %08x\n", hr);
1523     if (hr != S_OK)
1524         return;
1525 
1526     /* On windows, we expect CLSID_ShellFSFolder. On wine we relax this constraint
1527      * a little bit and also allow CLSID_UnixDosFolder. */
1528     hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1529     ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1530     ok(IsEqualCLSID(&clsid, &CLSID_ShellFSFolder) || IsEqualCLSID(&clsid, &CLSID_UnixDosFolder),
1531         "IPersistFolder3::GetClassID returned unexpected CLSID!\n");
1532 
1533     IPersistFolder3_Release(pPersistFolder3);
1534 }
1535 
1536 #include "pshpack1.h"
1537 struct FileStructA {
1538     BYTE  type;
1539     BYTE  dummy;
1540     DWORD dwFileSize;
1541     WORD  uFileDate;    /* In our current implementation this is */
1542     WORD  uFileTime;    /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastWriteTime) */
1543     WORD  uFileAttribs;
1544     CHAR  szName[1];
1545 };
1546 
1547 struct FileStructW {
1548     WORD  cbLen;        /* Length of this element. */
1549     BYTE  abFooBar1[6]; /* Beyond any recognition. */
1550     WORD  uDate;        /* FileTimeToDosDate(WIN32_FIND_DATA->ftCreationTime)? */
1551     WORD  uTime;        /* (this is currently speculation) */
1552     WORD  uDate2;       /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastAccessTime)? */
1553     WORD  uTime2;       /* (this is currently speculation) */
1554     BYTE  abFooBar2[4]; /* Beyond any recognition. */
1555     WCHAR wszName[1];   /* The long filename in unicode. */
1556     /* Just for documentation: Right after the unicode string: */
1557     WORD  cbOffset;     /* FileStructW's offset from the beginning of the SHITMEID.
1558                          * SHITEMID->cb == uOffset + cbLen */
1559 };
1560 #include "poppack.h"
1561 
test_ITEMIDLIST_format(void)1562 static void test_ITEMIDLIST_format(void) {
1563     WCHAR wszPersonal[MAX_PATH];
1564     LPSHELLFOLDER psfDesktop, psfPersonal;
1565     LPITEMIDLIST pidlPersonal, pidlFile;
1566     HANDLE hFile;
1567     HRESULT hr;
1568     BOOL bResult;
1569     WCHAR wszFile[3][17] = { { 'e','v','e','n','_',0 }, { 'o','d','d','_',0 },
1570         { 'l','o','n','g','e','r','_','t','h','a','n','.','8','_','3',0 } };
1571     int i;
1572 
1573     bResult = SHGetSpecialFolderPathW(NULL, wszPersonal, CSIDL_PERSONAL, FALSE);
1574     ok(bResult, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1575     if (!bResult) return;
1576 
1577     SetLastError(0xdeadbeef);
1578     bResult = SetCurrentDirectoryW(wszPersonal);
1579     if (!bResult && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
1580         win_skip("Most W-calls are not implemented\n");
1581         return;
1582     }
1583     ok(bResult, "SetCurrentDirectory failed! Last error: %u\n", GetLastError());
1584     if (!bResult) return;
1585 
1586     hr = SHGetDesktopFolder(&psfDesktop);
1587     ok(hr == S_OK, "SHGetDesktopFolder failed! hr: %08x\n", hr);
1588     if (hr != S_OK) return;
1589 
1590     hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszPersonal, NULL, &pidlPersonal, NULL);
1591     ok(hr == S_OK, "psfDesktop->ParseDisplayName failed! hr = %08x\n", hr);
1592     if (hr != S_OK) {
1593         IShellFolder_Release(psfDesktop);
1594         return;
1595     }
1596 
1597     hr = IShellFolder_BindToObject(psfDesktop, pidlPersonal, NULL, &IID_IShellFolder,
1598         (LPVOID*)&psfPersonal);
1599     IShellFolder_Release(psfDesktop);
1600     ILFree(pidlPersonal);
1601     ok(hr == S_OK, "psfDesktop->BindToObject failed! hr = %08x\n", hr);
1602     if (hr != S_OK) return;
1603 
1604     for (i=0; i<3; i++) {
1605         CHAR szFile[MAX_PATH];
1606         struct FileStructA *pFileStructA;
1607         WORD cbOffset;
1608 
1609         WideCharToMultiByte(CP_ACP, 0, wszFile[i], -1, szFile, MAX_PATH, NULL, NULL);
1610 
1611         hFile = CreateFileW(wszFile[i], GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_FLAG_WRITE_THROUGH, NULL);
1612         ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed! (%u)\n", GetLastError());
1613         if (hFile == INVALID_HANDLE_VALUE) {
1614             IShellFolder_Release(psfPersonal);
1615             return;
1616         }
1617         CloseHandle(hFile);
1618 
1619         hr = IShellFolder_ParseDisplayName(psfPersonal, NULL, NULL, wszFile[i], NULL, &pidlFile, NULL);
1620         DeleteFileW(wszFile[i]);
1621         ok(hr == S_OK, "psfPersonal->ParseDisplayName failed! hr: %08x\n", hr);
1622         if (hr != S_OK) {
1623             IShellFolder_Release(psfPersonal);
1624             return;
1625         }
1626 
1627         pFileStructA = (struct FileStructA *)pidlFile->mkid.abID;
1628         ok(pFileStructA->type == 0x32, "PIDLTYPE should be 0x32!\n");
1629         ok(pFileStructA->dummy == 0x00, "Dummy Byte should be 0x00!\n");
1630         ok(pFileStructA->dwFileSize == 0, "Filesize should be zero!\n");
1631 
1632         if (i < 2) /* First two file names are already in valid 8.3 format */
1633             ok(!strcmp(szFile, (CHAR*)&pidlFile->mkid.abID[12]), "Wrong file name!\n");
1634         else
1635             /* WinXP stores a derived 8.3 dos name (LONGER~1.8_3) here. We probably
1636              * can't implement this correctly, since unix filesystems don't support
1637              * this nasty short/long filename stuff. So we'll probably stay with our
1638              * current habit of storing the long filename here, which seems to work
1639              * just fine. */
1640             todo_wine
1641             ok(pidlFile->mkid.abID[18] == '~', "Should be derived 8.3 name!\n");
1642 
1643         if (i == 0) /* First file name has an even number of chars. No need for alignment. */
1644             ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] != '\0',
1645                 "Alignment byte, where there shouldn't be!\n");
1646 
1647         if (i == 1) /* Second file name has an uneven number of chars => alignment byte */
1648             ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] == '\0',
1649                 "There should be an alignment byte, but isn't!\n");
1650 
1651         /* The offset of the FileStructW member is stored as a WORD at the end of the pidl. */
1652         cbOffset = *(WORD*)(((LPBYTE)pidlFile)+pidlFile->mkid.cb-sizeof(WORD));
1653         ok ((cbOffset >= sizeof(struct FileStructA) &&
1654             cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW)),
1655             "Wrong offset value (%d) stored at the end of the PIDL\n", cbOffset);
1656 
1657         if (cbOffset >= sizeof(struct FileStructA) &&
1658             cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW))
1659         {
1660             struct FileStructW *pFileStructW = (struct FileStructW *)(((LPBYTE)pidlFile)+cbOffset);
1661             WCHAR *name = pFileStructW->wszName;
1662 
1663             ok(pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen,
1664                 "FileStructW's offset and length should add up to the PIDL's length!\n");
1665 
1666             if (pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen) {
1667                 /* Since we just created the file, time of creation,
1668                  * time of last access and time of last write access just be the same.
1669                  * These tests seem to fail sometimes (on WinXP), if the test is run again shortly
1670                  * after the first run. I do remember something with NTFS keeping the creation time
1671                  * if a file is deleted and then created again within a couple of seconds or so.
1672                  * Might be the reason. */
1673                 ok (pFileStructA->uFileDate == pFileStructW->uDate &&
1674                     pFileStructA->uFileTime == pFileStructW->uTime,
1675                     "Last write time should match creation time!\n");
1676 
1677                 /* On FAT filesystems the last access time is midnight
1678                    local time, so the values of uDate2 and uTime2 will
1679                    depend on the local timezone.  If the times are exactly
1680                    equal then the dates should be identical for both FAT
1681                    and NTFS as no timezone is more than 1 day away from UTC.
1682                 */
1683                 if (pFileStructA->uFileTime == pFileStructW->uTime2)
1684                 {
1685                     ok (pFileStructA->uFileDate == pFileStructW->uDate2,
1686                         "Last write date and time should match last access date and time!\n");
1687                 }
1688                 else
1689                 {
1690                     /* Filesystem may be FAT. Check date within 1 day
1691                        and seconds are zero. */
1692                     trace ("Filesystem may be FAT. Performing less strict atime test.\n");
1693                     ok ((pFileStructW->uTime2 & 0x1F) == 0,
1694                         "Last access time on FAT filesystems should have zero seconds.\n");
1695                     /* TODO: Perform check for date being within one day.*/
1696                 }
1697 
1698                 ok (!lstrcmpW(wszFile[i], name) ||
1699                     !lstrcmpW(wszFile[i], name + 9)  || /* Vista */
1700                     !lstrcmpW(wszFile[i], name + 11) || /* Win7 */
1701                     !lstrcmpW(wszFile[i], name + 13),   /* Win8 */
1702                     "The filename should be stored in unicode at this position!\n");
1703             }
1704         }
1705 
1706         ILFree(pidlFile);
1707     }
1708 
1709     IShellFolder_Release(psfPersonal);
1710 }
1711 
test_SHGetFolderPathA(void)1712 static void test_SHGetFolderPathA(void)
1713 {
1714     static const BOOL is_win64 = sizeof(void *) > sizeof(int);
1715     BOOL is_wow64;
1716     char path[MAX_PATH];
1717     char path_x86[MAX_PATH];
1718     char path_key[MAX_PATH];
1719     HRESULT hr;
1720     HKEY key;
1721 
1722     if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
1723 
1724     hr = SHGetFolderPathA( 0, CSIDL_PROGRAM_FILES, 0, SHGFP_TYPE_CURRENT, path );
1725     ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr );
1726     hr = SHGetFolderPathA( 0, CSIDL_PROGRAM_FILESX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
1727     if (hr == E_FAIL)
1728     {
1729         win_skip( "Program Files (x86) not supported\n" );
1730         return;
1731     }
1732     ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr );
1733     if (is_win64)
1734     {
1735         ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1736         ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1737         ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1738     }
1739     else
1740     {
1741         ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1742         if (is_wow64)
1743             ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1744         else
1745             ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1746     }
1747     if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1748     {
1749         DWORD type, count = sizeof(path_x86);
1750         if (!RegQueryValueExA( key, "ProgramFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1751         {
1752             ok( is_win64 || is_wow64, "ProgramFilesDir (x86) exists on 32-bit setup\n" );
1753             ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1754         }
1755         else ok( !is_win64 && !is_wow64, "ProgramFilesDir (x86) should exist on 64-bit setup\n" );
1756         RegCloseKey( key );
1757     }
1758 
1759     hr = SHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMON, 0, SHGFP_TYPE_CURRENT, path );
1760     ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr );
1761     hr = SHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMONX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
1762     if (hr == E_FAIL)
1763     {
1764         win_skip( "Common Files (x86) not supported\n" );
1765         return;
1766     }
1767     ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr );
1768     if (is_win64)
1769     {
1770         ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1771         ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1772         ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1773     }
1774     else
1775     {
1776         ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1777         if (is_wow64)
1778             ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1779         else
1780             ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1781     }
1782     if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1783     {
1784         DWORD type, count = sizeof(path_x86);
1785         if (!RegQueryValueExA( key, "CommonFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1786         {
1787             ok( is_win64 || is_wow64, "CommonFilesDir (x86) exists on 32-bit setup\n" );
1788             ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1789         }
1790         else ok( !is_win64 && !is_wow64, "CommonFilesDir (x86) should exist on 64-bit setup\n" );
1791     }
1792 }
1793 
test_SHGetFolderPathAndSubDirA(void)1794 static void test_SHGetFolderPathAndSubDirA(void)
1795 {
1796     HRESULT ret;
1797     BOOL delret;
1798     DWORD dwret;
1799     int i;
1800     static const char wine[] = "wine";
1801     static const char winetemp[] = "wine\\temp";
1802     static char appdata[MAX_PATH];
1803     static char testpath[MAX_PATH];
1804     static char toolongpath[MAX_PATH+1];
1805 
1806     if(FAILED(SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdata)))
1807     {
1808         win_skip("SHGetFolderPathA failed for CSIDL_LOCAL_APPDATA!\n");
1809         return;
1810     }
1811 
1812     sprintf(testpath, "%s\\%s", appdata, winetemp);
1813     delret = RemoveDirectoryA(testpath);
1814     if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) ) {
1815         win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1816         return;
1817     }
1818 
1819     sprintf(testpath, "%s\\%s", appdata, wine);
1820     delret = RemoveDirectoryA(testpath);
1821     if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) && (ERROR_FILE_NOT_FOUND != GetLastError())) {
1822         win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1823         return;
1824     }
1825 
1826     /* test invalid second parameter */
1827     ret = SHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | 0xff, NULL, SHGFP_TYPE_CURRENT, wine, testpath);
1828     ok(E_INVALIDARG == ret, "expected E_INVALIDARG, got  %x\n", ret);
1829 
1830     /* test fourth parameter */
1831     ret = SHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, 2, winetemp, testpath);
1832     switch(ret) {
1833         case S_OK: /* winvista */
1834             ok(!strncmp(appdata, testpath, strlen(appdata)),
1835                 "expected %s to start with %s\n", testpath, appdata);
1836             ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1837                 "expected %s to end with %s\n", testpath, winetemp);
1838             break;
1839         case E_INVALIDARG: /* winxp, win2k3 */
1840             break;
1841         default:
1842             ok(0, "expected S_OK or E_INVALIDARG, got  %x\n", ret);
1843     }
1844 
1845     /* test fifth parameter */
1846     testpath[0] = '\0';
1847     ret = SHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, NULL, testpath);
1848     ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1849     ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1850 
1851     testpath[0] = '\0';
1852     ret = SHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "", testpath);
1853     ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1854     ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1855 
1856     testpath[0] = '\0';
1857     ret = SHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "\\", testpath);
1858     ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1859     ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1860 
1861     for(i=0; i< MAX_PATH; i++)
1862         toolongpath[i] = '0' + i % 10;
1863     toolongpath[MAX_PATH] = '\0';
1864     ret = SHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, toolongpath, testpath);
1865     ok(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) == ret,
1866         "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), ret);
1867 
1868     testpath[0] = '\0';
1869     ret = SHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wine, NULL);
1870     ok((S_OK == ret) || (E_INVALIDARG == ret), "expected S_OK or E_INVALIDARG, got %x\n", ret);
1871 
1872     /* test a not existing path */
1873     testpath[0] = '\0';
1874     ret = SHGetFolderPathAndSubDirA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
1875     ok(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == ret,
1876         "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), ret);
1877 
1878     /* create a directory inside a not existing directory */
1879     testpath[0] = '\0';
1880     ret = SHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_CREATE | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
1881     ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1882     ok(!strncmp(appdata, testpath, strlen(appdata)),
1883         "expected %s to start with %s\n", testpath, appdata);
1884     ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1885         "expected %s to end with %s\n", testpath, winetemp);
1886     dwret = GetFileAttributesA(testpath);
1887     ok(FILE_ATTRIBUTE_DIRECTORY | dwret, "expected %x to contain FILE_ATTRIBUTE_DIRECTORY\n", dwret);
1888 
1889     /* cleanup */
1890     sprintf(testpath, "%s\\%s", appdata, winetemp);
1891     RemoveDirectoryA(testpath);
1892     sprintf(testpath, "%s\\%s", appdata, wine);
1893     RemoveDirectoryA(testpath);
1894 }
1895 
test_LocalizedNames(void)1896 static void test_LocalizedNames(void)
1897 {
1898     static char cCurrDirA[MAX_PATH];
1899     WCHAR cCurrDirW[MAX_PATH], tempbufW[25];
1900     IShellFolder *IDesktopFolder, *testIShellFolder;
1901     ITEMIDLIST *newPIDL;
1902     int len;
1903     HRESULT hr;
1904     static char resourcefile[MAX_PATH];
1905     DWORD res;
1906     HANDLE file;
1907     STRRET strret;
1908     BOOL ret;
1909 
1910     static const char desktopini_contents1[] =
1911         "[.ShellClassInfo]\r\n"
1912         "LocalizedResourceName=@";
1913     static const char desktopini_contents2[] =
1914         ",-1\r\n";
1915     static WCHAR foldernameW[] = {'t','e','s','t','f','o','l','d','e','r',0};
1916     static const WCHAR folderdisplayW[] = {'F','o','l','d','e','r',' ','N','a','m','e',' ','R','e','s','o','u','r','c','e',0};
1917 
1918     /* create folder with desktop.ini and localized name in GetModuleFileNameA(NULL) */
1919     CreateDirectoryA(".\\testfolder", NULL);
1920 
1921     SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")|FILE_ATTRIBUTE_SYSTEM);
1922 
1923     GetModuleFileNameA(NULL, resourcefile, MAX_PATH);
1924 
1925     file = CreateFileA(".\\testfolder\\desktop.ini", GENERIC_WRITE, 0, NULL,
1926                          CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1927     ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %i\n", GetLastError());
1928     ret = WriteFile(file, desktopini_contents1, strlen(desktopini_contents1), &res, NULL) &&
1929           WriteFile(file, resourcefile, strlen(resourcefile), &res, NULL) &&
1930           WriteFile(file, desktopini_contents2, strlen(desktopini_contents2), &res, NULL);
1931     ok(ret, "WriteFile failed %i\n", GetLastError());
1932     CloseHandle(file);
1933 
1934     /* get IShellFolder for parent */
1935     GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1936     len = lstrlenA(cCurrDirA);
1937 
1938     if (len == 0) {
1939         win_skip("GetCurrentDirectoryA returned empty string. Skipping test_LocalizedNames\n");
1940         goto cleanup;
1941     }
1942     if(cCurrDirA[len-1] == '\\')
1943         cCurrDirA[len-1] = 0;
1944 
1945     MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1946 
1947     hr = SHGetDesktopFolder(&IDesktopFolder);
1948     ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1949 
1950     hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1951     ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1952 
1953     hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1954     ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1955 
1956     IMalloc_Free(ppM, newPIDL);
1957 
1958     /* windows reads the display name from the resource */
1959     hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, foldernameW, NULL, &newPIDL, 0);
1960     ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1961 
1962     hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER, &strret);
1963     ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1964 
1965     hr = StrRetToBufW(&strret, newPIDL, tempbufW, ARRAY_SIZE(tempbufW));
1966     ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1967     todo_wine
1968     ok (!lstrcmpiW(tempbufW, folderdisplayW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1969 
1970     /* editing name is also read from the resource */
1971     hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FOREDITING, &strret);
1972     ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1973 
1974     hr = StrRetToBufW(&strret, newPIDL, tempbufW, ARRAY_SIZE(tempbufW));
1975     ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1976     todo_wine
1977     ok (!lstrcmpiW(tempbufW, folderdisplayW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1978 
1979     /* parsing name is unchanged */
1980     hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FORPARSING, &strret);
1981     ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1982 
1983     hr = StrRetToBufW(&strret, newPIDL, tempbufW, ARRAY_SIZE(tempbufW));
1984     ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1985     ok (!lstrcmpiW(tempbufW, foldernameW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1986 
1987     IShellFolder_Release(IDesktopFolder);
1988     IShellFolder_Release(testIShellFolder);
1989 
1990     IMalloc_Free(ppM, newPIDL);
1991 
1992 cleanup:
1993     DeleteFileA(".\\testfolder\\desktop.ini");
1994     SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")&~FILE_ATTRIBUTE_SYSTEM);
1995     RemoveDirectoryA(".\\testfolder");
1996 }
1997 
test_SHCreateShellItem(void)1998 static void test_SHCreateShellItem(void)
1999 {
2000     IShellItem *shellitem, *shellitem2;
2001     IPersistIDList *persistidl;
2002     LPITEMIDLIST pidl_cwd=NULL, pidl_testfile, pidl_abstestfile, pidl_test, pidl_desktop;
2003     HRESULT ret;
2004     char curdirA[MAX_PATH];
2005     WCHAR curdirW[MAX_PATH];
2006     WCHAR fnbufW[MAX_PATH];
2007     IShellFolder *desktopfolder=NULL, *currentfolder=NULL;
2008     static WCHAR testfileW[] = {'t','e','s','t','f','i','l','e',0};
2009 
2010     GetCurrentDirectoryA(MAX_PATH, curdirA);
2011 
2012     if (!pSHCreateShellItem)
2013     {
2014         win_skip("SHCreateShellItem isn't available\n");
2015         return;
2016     }
2017 
2018     if (!curdirA[0])
2019     {
2020         win_skip("GetCurrentDirectoryA returned empty string, skipping test_SHCreateShellItem\n");
2021         return;
2022     }
2023 
2024     ret = SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
2025     ok(ret == S_OK, "Got 0x%08x\n", ret);
2026 
2027     MultiByteToWideChar(CP_ACP, 0, curdirA, -1, curdirW, MAX_PATH);
2028 
2029     ret = SHGetDesktopFolder(&desktopfolder);
2030     ok(SUCCEEDED(ret), "SHGetShellFolder returned %x\n", ret);
2031 
2032     ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2033     ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2034 
2035     ret = IShellFolder_BindToObject(desktopfolder, pidl_cwd, NULL, &IID_IShellFolder, (void**)&currentfolder);
2036     ok(SUCCEEDED(ret), "BindToObject returned %x\n", ret);
2037 
2038     CreateTestFile(".\\testfile");
2039 
2040     ret = IShellFolder_ParseDisplayName(currentfolder, NULL, NULL, testfileW, NULL, &pidl_testfile, NULL);
2041     ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2042 
2043     pidl_abstestfile = ILCombine(pidl_cwd, pidl_testfile);
2044 
2045     shellitem = (void*)0xdeadbeef;
2046     ret = pSHCreateShellItem(NULL, NULL, NULL, &shellitem);
2047     ok(ret == E_INVALIDARG, "SHCreateShellItem returned %x\n", ret);
2048     ok(shellitem == 0, "Got %p\n", shellitem);
2049 
2050     if (0) /* crashes on Windows XP */
2051     {
2052         pSHCreateShellItem(NULL, NULL, pidl_cwd, NULL);
2053         pSHCreateShellItem(pidl_cwd, NULL, NULL, &shellitem);
2054         pSHCreateShellItem(NULL, currentfolder, NULL, &shellitem);
2055         pSHCreateShellItem(pidl_cwd, currentfolder, NULL, &shellitem);
2056     }
2057 
2058     ret = pSHCreateShellItem(NULL, NULL, pidl_cwd, &shellitem);
2059     ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2060     if (SUCCEEDED(ret))
2061     {
2062         ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2063         ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2064         if (SUCCEEDED(ret))
2065         {
2066             ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2067             ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2068             if (SUCCEEDED(ret))
2069             {
2070                 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2071                 ILFree(pidl_test);
2072             }
2073             IPersistIDList_Release(persistidl);
2074         }
2075         IShellItem_Release(shellitem);
2076     }
2077 
2078     ret = pSHCreateShellItem(pidl_cwd, NULL, pidl_testfile, &shellitem);
2079     ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2080     if (SUCCEEDED(ret))
2081     {
2082         ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2083         ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2084         if (SUCCEEDED(ret))
2085         {
2086             ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2087             ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2088             if (SUCCEEDED(ret))
2089             {
2090                 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2091                 ILFree(pidl_test);
2092             }
2093             IPersistIDList_Release(persistidl);
2094         }
2095 
2096         ret = IShellItem_GetParent(shellitem, &shellitem2);
2097         ok(SUCCEEDED(ret), "GetParent returned %x\n", ret);
2098         if (SUCCEEDED(ret))
2099         {
2100             ret = IShellItem_QueryInterface(shellitem2, &IID_IPersistIDList, (void**)&persistidl);
2101             ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2102             if (SUCCEEDED(ret))
2103             {
2104                 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2105                 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2106                 if (SUCCEEDED(ret))
2107                 {
2108                     ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2109                     ILFree(pidl_test);
2110                 }
2111                 IPersistIDList_Release(persistidl);
2112             }
2113             IShellItem_Release(shellitem2);
2114         }
2115 
2116         IShellItem_Release(shellitem);
2117     }
2118 
2119     ret = pSHCreateShellItem(NULL, currentfolder, pidl_testfile, &shellitem);
2120     ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2121     if (SUCCEEDED(ret))
2122     {
2123         ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2124         ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2125         if (SUCCEEDED(ret))
2126         {
2127             ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2128             ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2129             if (SUCCEEDED(ret))
2130             {
2131                 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2132                 ILFree(pidl_test);
2133             }
2134             IPersistIDList_Release(persistidl);
2135         }
2136         IShellItem_Release(shellitem);
2137     }
2138 
2139     /* if a parent pidl and shellfolder are specified, the shellfolder is ignored */
2140     ret = pSHCreateShellItem(pidl_cwd, desktopfolder, pidl_testfile, &shellitem);
2141     ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2142     if (SUCCEEDED(ret))
2143     {
2144         ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2145         ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2146         if (SUCCEEDED(ret))
2147         {
2148             ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2149             ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2150             if (SUCCEEDED(ret))
2151             {
2152                 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2153                 ILFree(pidl_test);
2154             }
2155             IPersistIDList_Release(persistidl);
2156         }
2157         IShellItem_Release(shellitem);
2158     }
2159 
2160     ret = pSHCreateShellItem(NULL, desktopfolder, pidl_testfile, &shellitem);
2161     ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2162     if (SUCCEEDED(ret))
2163     {
2164         ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2165         ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2166         if (SUCCEEDED(ret))
2167         {
2168             ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2169             ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2170             if (SUCCEEDED(ret))
2171             {
2172                 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2173                 ILFree(pidl_test);
2174             }
2175             IPersistIDList_Release(persistidl);
2176         }
2177 
2178         IShellItem_Release(shellitem);
2179     }
2180 
2181     ret = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
2182     ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2183     if (SUCCEEDED(ret))
2184     {
2185         ret = IShellItem_GetParent(shellitem, &shellitem2);
2186         ok(FAILED(ret), "Got 0x%08x\n", ret);
2187         if(SUCCEEDED(ret)) IShellItem_Release(shellitem2);
2188         IShellItem_Release(shellitem);
2189     }
2190 
2191     /* SHCreateItemFromParsingName */
2192     if(pSHCreateItemFromParsingName)
2193     {
2194         if(0)
2195         {
2196             /* Crashes under windows 7 */
2197             pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, NULL);
2198         }
2199 
2200         shellitem = (void*)0xdeadbeef;
2201         ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, (void**)&shellitem);
2202         ok(ret == E_INVALIDARG, "SHCreateItemFromParsingName returned %x\n", ret);
2203         ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2204 
2205         ret = pSHCreateItemFromParsingName(testfileW, NULL, &IID_IShellItem, (void**)&shellitem);
2206         ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
2207            "SHCreateItemFromParsingName returned %x\n", ret);
2208         if(SUCCEEDED(ret)) IShellItem_Release(shellitem);
2209 
2210         lstrcpyW(fnbufW, curdirW);
2211         myPathAddBackslashW(fnbufW);
2212         lstrcatW(fnbufW, testfileW);
2213 
2214         ret = pSHCreateItemFromParsingName(fnbufW, NULL, &IID_IShellItem, (void**)&shellitem);
2215         ok(ret == S_OK, "SHCreateItemFromParsingName returned %x\n", ret);
2216         if(SUCCEEDED(ret))
2217         {
2218             LPWSTR tmp_fname;
2219             ret = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &tmp_fname);
2220             ok(ret == S_OK, "GetDisplayName returned %x\n", ret);
2221             if(SUCCEEDED(ret))
2222             {
2223                 ok(!lstrcmpW(fnbufW, tmp_fname), "strings not equal\n");
2224                 CoTaskMemFree(tmp_fname);
2225             }
2226             IShellItem_Release(shellitem);
2227         }
2228     }
2229     else
2230         win_skip("No SHCreateItemFromParsingName\n");
2231 
2232 
2233     /* SHCreateItemFromIDList */
2234     if(pSHCreateItemFromIDList)
2235     {
2236         if(0)
2237         {
2238             /* Crashes under win7 */
2239             pSHCreateItemFromIDList(NULL, &IID_IShellItem, NULL);
2240         }
2241 
2242         ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, (void**)&shellitem);
2243         ok(ret == E_INVALIDARG, "SHCreateItemFromIDList returned %x\n", ret);
2244 
2245         ret = pSHCreateItemFromIDList(pidl_cwd, &IID_IShellItem, (void**)&shellitem);
2246         ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2247         if (SUCCEEDED(ret))
2248         {
2249             ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2250             ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2251             if (SUCCEEDED(ret))
2252             {
2253                 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2254                 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2255                 if (SUCCEEDED(ret))
2256                 {
2257                     ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2258                     ILFree(pidl_test);
2259                 }
2260                 IPersistIDList_Release(persistidl);
2261             }
2262             IShellItem_Release(shellitem);
2263         }
2264 
2265         ret = pSHCreateItemFromIDList(pidl_testfile, &IID_IShellItem, (void**)&shellitem);
2266         ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2267         if (SUCCEEDED(ret))
2268         {
2269             ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2270             ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2271             if (SUCCEEDED(ret))
2272             {
2273                 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2274                 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2275                 if (SUCCEEDED(ret))
2276                 {
2277                     ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2278                     ILFree(pidl_test);
2279                 }
2280                 IPersistIDList_Release(persistidl);
2281             }
2282             IShellItem_Release(shellitem);
2283         }
2284     }
2285     else
2286         win_skip("No SHCreateItemFromIDList\n");
2287 
2288     /* SHCreateItemFromRelativeName */
2289     if(pSHCreateItemFromRelativeName && pSHGetKnownFolderPath)
2290     {
2291         IShellItem *shellitem_desktop = NULL;
2292         WCHAR *desktop_path, *displayname;
2293         WCHAR testfile_path[MAX_PATH] = {0};
2294         HANDLE file;
2295         LPITEMIDLIST pidl_desktop_testfile = NULL;
2296         int order;
2297 
2298         ret = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem_desktop);
2299         ok(ret == S_OK, "SHCreateShellItem failed: 0x%08x.\n", ret);
2300 
2301         shellitem = (void*)0xdeadbeef;
2302         ret = pSHCreateItemFromRelativeName(shellitem_desktop, NULL, NULL, &IID_IShellItem,
2303                                             (void**)&shellitem);
2304         ok(ret == E_INVALIDARG, "Expected 0x%08x but SHCreateItemFromRelativeName return: 0x%08x.\n",
2305            E_INVALIDARG, ret);
2306         ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2307 
2308         /* Test with a non-existent file */
2309         shellitem = (void*)0xdeadbeef;
2310         ret = pSHCreateItemFromRelativeName(shellitem_desktop, testfileW, NULL, &IID_IShellItem,
2311                                             (void**)&shellitem);
2312         ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
2313            "Expected 0x%08x but SHCreateItemFromRelativeName return: 0x%08x.\n",
2314            HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), ret);
2315         ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2316 
2317         /* Create a file for testing in desktop folder */
2318         pSHGetKnownFolderPath(&FOLDERID_Desktop, 0, NULL, &desktop_path);
2319         lstrcatW(testfile_path, desktop_path);
2320         myPathAddBackslashW(testfile_path);
2321         lstrcatW(testfile_path, testfileW);
2322         file = CreateFileW(testfile_path, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
2323         ok(file != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: 0x%08x.\n", GetLastError());
2324         CloseHandle(file);
2325 
2326         shellitem = (void*)0xdeadbeef;
2327         ret = pSHCreateItemFromRelativeName(shellitem_desktop, testfileW, NULL, &IID_IShellItem,
2328                                             (void**)&shellitem);
2329         ok(ret == S_OK, "SHCreateItemFromRelativeName failed: 0x%08x.\n", ret);
2330         ok(shellitem != NULL, "shellitem was %p.\n", shellitem);
2331         if(SUCCEEDED(ret))
2332         {
2333             ret = IShellItem_GetDisplayName(shellitem, 0, &displayname);
2334             ok(ret == S_OK, "IShellItem_GetDisplayName failed: 0x%08x.\n", ret);
2335             ok(!lstrcmpW(displayname, testfileW), "got wrong display name: %s.\n", wine_dbgstr_w(displayname));
2336             CoTaskMemFree(displayname);
2337 
2338             shellitem2 = (void*)0xdeadbeef;
2339             ret = pSHCreateItemFromRelativeName(shellitem_desktop, testfileW, NULL, &IID_IShellItem,
2340                                                 (void**)&shellitem2);
2341             ok(ret == S_OK, "SHCreateItemFromRelativeName failed: 0x%08x.\n", ret);
2342             ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2343             ok(ret == S_OK, "IShellItem_Compare failed: 0x%08x.\n", ret);
2344             ok(!order, "order got wrong value: %d.\n", order);
2345             IShellItem_Release(shellitem2);
2346 
2347             shellitem2 = (void*)0xdeadbeef;
2348             ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, testfileW, NULL,
2349                                                 &pidl_desktop_testfile, NULL);
2350             ok(ret == S_OK, "ParseDisplayName failed 0x%08x.\n", ret);
2351             ret = pSHCreateItemFromIDList(pidl_desktop_testfile, &IID_IShellItem, (void**)&shellitem2);
2352             ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2353             ok(ret == S_OK, "IShellItem_Compare fail: 0x%08x.\n", ret);
2354             ok(!order, "order got wrong value: %d.\n", order);
2355             ILFree(pidl_desktop_testfile);
2356             IShellItem_Release(shellitem2);
2357 
2358             IShellItem_Release(shellitem);
2359         }
2360 
2361         DeleteFileW(testfile_path);
2362         CoTaskMemFree(desktop_path);
2363         IShellItem_Release(shellitem_desktop);
2364     }
2365     else
2366         win_skip("No SHCreateItemFromRelativeName or SHGetKnownFolderPath\n");
2367 
2368     /* SHCreateItemInKnownFolder */
2369     if(pSHCreateItemInKnownFolder && pSHGetKnownFolderPath)
2370     {
2371         WCHAR *desktop_path;
2372         WCHAR testfile_path[MAX_PATH] = {0};
2373         HANDLE file;
2374         WCHAR *displayname = NULL;
2375         int order;
2376         LPITEMIDLIST pidl_desktop_testfile = NULL;
2377 
2378         shellitem = (void*)0xdeadbeef;
2379         ret = pSHCreateItemInKnownFolder(&FOLDERID_Desktop, 0, NULL, &IID_IShellItem,
2380                                          (void**)&shellitem);
2381         ok(ret == S_OK, "SHCreateItemInKnownFolder failed: 0x%08x.\n", ret);
2382         ok(shellitem != NULL, "shellitem was %p.\n", shellitem);
2383         if(SUCCEEDED(ret))
2384         {
2385             shellitem2 = (void*)0xdeadbeef;
2386             ret = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem2);
2387             ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2388             if(SUCCEEDED(ret))
2389             {
2390                 ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2391                 ok(ret == S_OK, "IShellItem_Compare failed: 0x%08x.\n", ret);
2392                 ok(!order, "order got wrong value: %d.\n", order);
2393                 IShellItem_Release(shellitem2);
2394             }
2395             IShellItem_Release(shellitem);
2396         }
2397 
2398         /* Test with a non-existent file */
2399         shellitem = (void*)0xdeadbeef;
2400         ret = pSHCreateItemInKnownFolder(&FOLDERID_Desktop, 0, testfileW, &IID_IShellItem,
2401                                          (void**)&shellitem);
2402         ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
2403            "Expected 0x%08x but SHCreateItemInKnownFolder return: 0x%08x.\n",
2404            HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), ret);
2405         ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2406 
2407         pSHGetKnownFolderPath(&FOLDERID_Desktop, 0, NULL, &desktop_path);
2408         lstrcatW(testfile_path, desktop_path);
2409         myPathAddBackslashW(testfile_path);
2410         lstrcatW(testfile_path, testfileW);
2411         file = CreateFileW(testfile_path, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
2412         ok(file != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: 0x%08x.\n", GetLastError());
2413         CloseHandle(file);
2414 
2415         shellitem = (void*)0xdeadbeef;
2416         ret = pSHCreateItemInKnownFolder(&FOLDERID_Desktop, 0, testfileW, &IID_IShellItem,
2417                                          (void**)&shellitem);
2418         ok(ret == S_OK, "SHCreateItemInKnownFolder failed: 0x%08x.\n", ret);
2419         ok(shellitem != NULL, "shellitem was %p.\n", shellitem);
2420         if(SUCCEEDED(ret))
2421         {
2422             ret = IShellItem_GetDisplayName(shellitem, 0, &displayname);
2423             ok(ret == S_OK, "IShellItem_GetDisplayName failed: 0x%08x.\n", ret);
2424             ok(!lstrcmpW(displayname, testfileW), "got wrong display name: %s.\n",
2425                wine_dbgstr_w(displayname));
2426             CoTaskMemFree(displayname);
2427 
2428             shellitem2 = (void*)0xdeadbeef;
2429             ret = pSHCreateItemInKnownFolder(&FOLDERID_Desktop, 0, testfileW, &IID_IShellItem,
2430                                              (void**)&shellitem2);
2431             ok(ret == S_OK, "SHCreateItemInKnownFolder failed: 0x%08x.\n", ret);
2432             ok(shellitem2 != NULL, "shellitem was %p.\n", shellitem);
2433             ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2434             ok(ret == S_OK, "IShellItem_Compare failed: 0x%08x.\n", ret);
2435             ok(!order, "order got wrong value: %d.\n", order);
2436             IShellItem_Release(shellitem2);
2437 
2438             shellitem2 = (void*)0xdeadbeef;
2439             ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, testfileW, NULL,
2440                                                 &pidl_desktop_testfile, NULL);
2441             ok(SUCCEEDED(ret), "ParseDisplayName returned %x.\n", ret);
2442             ret = pSHCreateItemFromIDList(pidl_desktop_testfile, &IID_IShellItem, (void**)&shellitem2);
2443             ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2444             ok(ret == S_OK, "IShellItem_Compare failed: 0x%08x.\n", ret);
2445             ok(!order, "order got wrong value: %d.\n", order);
2446             ILFree(pidl_desktop_testfile);
2447             IShellItem_Release(shellitem2);
2448 
2449             IShellItem_Release(shellitem);
2450         }
2451 
2452         shellitem = (void*)0xdeadbeef;
2453         ret = pSHCreateItemInKnownFolder(&FOLDERID_Documents, 0, NULL, &IID_IShellItem,
2454                                          (void**)&shellitem);
2455         ok(ret == S_OK, "SHCreateItemInKnownFolder failed: 0x%08x.\n", ret);
2456         ok(shellitem != NULL, "shellitem was %p.\n", shellitem);
2457         if(SUCCEEDED(ret))
2458         {
2459             shellitem2 = (void*)0xdeadbeef;
2460             ret = pSHCreateItemInKnownFolder(&FOLDERID_Documents, 0, NULL, &IID_IShellItem,
2461                                              (void**)&shellitem2);
2462             ok(ret == S_OK, "SHCreateItemInKnownFolder failed: 0x%08x.\n", ret);
2463             ok(shellitem2 != NULL, "shellitem was %p.\n", shellitem);
2464             ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2465             ok(ret == S_OK, "IShellItem_Compare failed: 0x%08x.\n", ret);
2466             ok(!order, "order got wrong value: %d.\n", order);
2467             IShellItem_Release(shellitem2);
2468 
2469             IShellItem_Release(shellitem);
2470         }
2471         DeleteFileW(testfile_path);
2472         CoTaskMemFree(desktop_path);
2473     }
2474     else
2475         win_skip("No SHCreateItemInKnownFolder or SHGetKnownFolderPath\n");
2476 
2477     DeleteFileA(".\\testfile");
2478     ILFree(pidl_abstestfile);
2479     ILFree(pidl_testfile);
2480     ILFree(pidl_desktop);
2481     ILFree(pidl_cwd);
2482     IShellFolder_Release(currentfolder);
2483     IShellFolder_Release(desktopfolder);
2484 }
2485 
test_SHGetNameFromIDList(void)2486 static void test_SHGetNameFromIDList(void)
2487 {
2488     IShellItem *shellitem;
2489     LPITEMIDLIST pidl;
2490     LPWSTR name_string;
2491     HRESULT hres;
2492     UINT i;
2493     static const DWORD flags[] = {
2494         SIGDN_NORMALDISPLAY, SIGDN_PARENTRELATIVEPARSING,
2495         SIGDN_DESKTOPABSOLUTEPARSING,SIGDN_PARENTRELATIVEEDITING,
2496         SIGDN_DESKTOPABSOLUTEEDITING, /*SIGDN_FILESYSPATH, SIGDN_URL, */
2497         SIGDN_PARENTRELATIVEFORADDRESSBAR,SIGDN_PARENTRELATIVE, -1234};
2498 
2499     if(!pSHGetNameFromIDList)
2500     {
2501         win_skip("SHGetNameFromIDList missing.\n");
2502         return;
2503     }
2504 
2505     /* This should be available on any platform that passed the above test. */
2506     ok(pSHCreateShellItem != NULL, "SHCreateShellItem missing.\n");
2507 
2508     if(0)
2509     {
2510         /* Crashes under win7 */
2511         pSHGetNameFromIDList(NULL, 0, NULL);
2512     }
2513 
2514     hres = pSHGetNameFromIDList(NULL, 0, &name_string);
2515     ok(hres == E_INVALIDARG, "Got 0x%08x\n", hres);
2516 
2517     /* Test the desktop */
2518     hres = SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
2519     ok(hres == S_OK, "Got 0x%08x\n", hres);
2520     hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2521     ok(hres == S_OK, "Got 0x%08x\n", hres);
2522     if(SUCCEEDED(hres))
2523     {
2524         WCHAR *nameSI, *nameSH;
2525         WCHAR buf[MAX_PATH];
2526         HRESULT hrSI, hrSH, hrSF;
2527         STRRET strret;
2528         IShellFolder *psf;
2529         BOOL res;
2530 
2531         SHGetDesktopFolder(&psf);
2532         for(i = 0; flags[i] != -1234; i++)
2533         {
2534             hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2535             ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2536             hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2537             ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2538             hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2539             ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2540 
2541             if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2542                 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2543 
2544             if(SUCCEEDED(hrSF))
2545             {
2546                 StrRetToBufW(&strret, NULL, buf, MAX_PATH);
2547                 if(SUCCEEDED(hrSI))
2548                     ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2549                 if(SUCCEEDED(hrSF))
2550                     ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2551             }
2552             if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2553             if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2554         }
2555         IShellFolder_Release(psf);
2556 
2557         hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2558         ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2559         res = SHGetPathFromIDListW(pidl, buf);
2560         ok(res == TRUE, "Got %d\n", res);
2561         if(SUCCEEDED(hrSI) && res)
2562             ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2563         if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2564 
2565         hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2566         todo_wine ok(hres == S_OK, "Got 0x%08x\n", hres);
2567         if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2568 
2569         IShellItem_Release(shellitem);
2570     }
2571     ILFree(pidl);
2572 
2573     /* Test the control panel */
2574     hres = SHGetSpecialFolderLocation(NULL, CSIDL_CONTROLS, &pidl);
2575     ok(hres == S_OK, "Got 0x%08x\n", hres);
2576     hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2577     ok(hres == S_OK, "Got 0x%08x\n", hres);
2578     if(SUCCEEDED(hres))
2579     {
2580         WCHAR *nameSI, *nameSH;
2581         WCHAR buf[MAX_PATH];
2582         HRESULT hrSI, hrSH, hrSF;
2583         STRRET strret;
2584         IShellFolder *psf;
2585         BOOL res;
2586 
2587         SHGetDesktopFolder(&psf);
2588         for(i = 0; flags[i] != -1234; i++)
2589         {
2590             hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2591             ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2592             hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2593             ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2594             hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2595             ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2596 
2597             if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2598                 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2599 
2600             if(SUCCEEDED(hrSF))
2601             {
2602                 StrRetToBufW(&strret, NULL, buf, MAX_PATH);
2603                 if(SUCCEEDED(hrSI))
2604                     ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2605                 if(SUCCEEDED(hrSF))
2606                     ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2607             }
2608             if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2609             if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2610         }
2611         IShellFolder_Release(psf);
2612 
2613         hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2614         ok(hrSI == E_INVALIDARG, "Got 0x%08x\n", hrSI);
2615         res = SHGetPathFromIDListW(pidl, buf);
2616         ok(res == FALSE, "Got %d\n", res);
2617         if(SUCCEEDED(hrSI) && res)
2618             ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2619         if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2620 
2621         hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2622         todo_wine ok(hres == E_NOTIMPL /* Win7 */ || hres == S_OK /* Vista */,
2623                      "Got 0x%08x\n", hres);
2624         if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2625 
2626         IShellItem_Release(shellitem);
2627     }
2628     ILFree(pidl);
2629 }
2630 
test_SHGetItemFromDataObject(void)2631 static void test_SHGetItemFromDataObject(void)
2632 {
2633     IShellFolder *psfdesktop;
2634     IShellItem *psi;
2635     IShellView *psv;
2636     HRESULT hres;
2637 
2638     if(!pSHGetItemFromDataObject)
2639     {
2640         win_skip("No SHGetItemFromDataObject.\n");
2641         return;
2642     }
2643 
2644     if(0)
2645     {
2646         /* Crashes under win7 */
2647         pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, NULL);
2648     }
2649 
2650     hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, (void**)&psv);
2651     ok(hres == E_INVALIDARG, "got 0x%08x\n", hres);
2652 
2653     SHGetDesktopFolder(&psfdesktop);
2654 
2655     hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
2656     ok(hres == S_OK, "got 0x%08x\n", hres);
2657     if(SUCCEEDED(hres))
2658     {
2659         IEnumIDList *peidl;
2660         IDataObject *pdo;
2661         SHCONTF enum_flags;
2662 
2663         enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
2664         hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
2665         ok(hres == S_OK, "got 0x%08x\n", hres);
2666         if(SUCCEEDED(hres))
2667         {
2668             LPITEMIDLIST apidl[5];
2669             UINT count = 0, i;
2670 
2671             for(count = 0; count < 5; count++)
2672                 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
2673                     break;
2674 
2675             if(count)
2676             {
2677                 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
2678                                                   &IID_IDataObject, NULL, (void**)&pdo);
2679                 ok(hres == S_OK, "got 0x%08x\n", hres);
2680                 if(SUCCEEDED(hres))
2681                 {
2682                     hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2683                     ok(hres == S_OK, "got 0x%08x\n", hres);
2684                     if(SUCCEEDED(hres)) IShellItem_Release(psi);
2685                     hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2686                     ok(hres == S_OK, "got 0x%08x\n", hres);
2687                     if(SUCCEEDED(hres)) IShellItem_Release(psi);
2688                     hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2689                     ok(hres == S_OK, "got 0x%08x\n", hres);
2690                     if(SUCCEEDED(hres)) IShellItem_Release(psi);
2691                     hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2692                     ok(hres == S_OK, "got 0x%08x\n", hres);
2693                     if(SUCCEEDED(hres)) IShellItem_Release(psi);
2694                     hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2695                     ok(hres == S_OK, "got 0x%08x\n", hres);
2696                     if(SUCCEEDED(hres)) IShellItem_Release(psi);
2697 
2698                     IDataObject_Release(pdo);
2699                 }
2700             }
2701             else
2702                 skip("No file(s) found - skipping single-file test.\n");
2703 
2704             if(count > 1)
2705             {
2706                 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
2707                                                   &IID_IDataObject, NULL, (void**)&pdo);
2708                 ok(hres == S_OK, "got 0x%08x\n", hres);
2709                 if(SUCCEEDED(hres))
2710                 {
2711                     hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2712                     ok(hres == S_OK, "got 0x%08x\n", hres);
2713                     if(SUCCEEDED(hres)) IShellItem_Release(psi);
2714                     hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2715                     ok(hres == S_OK, "got 0x%08x\n", hres);
2716                     if(SUCCEEDED(hres)) IShellItem_Release(psi);
2717                     hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2718                     ok(hres == S_OK, "got 0x%08x\n", hres);
2719                     if(SUCCEEDED(hres)) IShellItem_Release(psi);
2720                     hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2721                     ok(hres == S_OK, "got 0x%08x\n", hres);
2722                     if(SUCCEEDED(hres)) IShellItem_Release(psi);
2723                     hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2724                     ok(hres == E_FAIL, "got 0x%08x\n", hres);
2725                     if(SUCCEEDED(hres)) IShellItem_Release(psi);
2726                     IDataObject_Release(pdo);
2727                 }
2728             }
2729             else
2730                 skip("zero or one file found - skipping multi-file test.\n");
2731 
2732             for(i = 0; i < count; i++)
2733                 ILFree(apidl[i]);
2734 
2735             IEnumIDList_Release(peidl);
2736         }
2737 
2738         IShellView_Release(psv);
2739     }
2740 
2741     IShellFolder_Release(psfdesktop);
2742 }
2743 
test_ShellItemCompare(void)2744 static void test_ShellItemCompare(void)
2745 {
2746     IShellItem *psi[9]; /* a\a, a\b, a\c, b\a, .. */
2747     IShellItem *psi_a = NULL, *psi_b = NULL, *psi_c = NULL;
2748     IShellFolder *psf_desktop, *psf_current;
2749     LPITEMIDLIST pidl_cwd;
2750     WCHAR curdirW[MAX_PATH];
2751     BOOL failed;
2752     HRESULT hr;
2753     static const WCHAR filesW[][9] = {
2754         {'a','\\','a',0}, {'a','\\','b',0}, {'a','\\','c',0},
2755         {'b','\\','a',0}, {'b','\\','b',0}, {'b','\\','c',0},
2756         {'c','\\','a',0}, {'c','\\','b',0}, {'c','\\','c',0} };
2757     int order;
2758     UINT i;
2759 
2760     if(!pSHCreateShellItem)
2761     {
2762         win_skip("SHCreateShellItem missing.\n");
2763         return;
2764     }
2765 
2766     GetCurrentDirectoryW(MAX_PATH, curdirW);
2767     if (!curdirW[0])
2768     {
2769         skip("Failed to get current directory, skipping.\n");
2770         return;
2771     }
2772 
2773     CreateDirectoryA(".\\a", NULL);
2774     CreateDirectoryA(".\\b", NULL);
2775     CreateDirectoryA(".\\c", NULL);
2776     CreateTestFile(".\\a\\a");
2777     CreateTestFile(".\\a\\b");
2778     CreateTestFile(".\\a\\c");
2779     CreateTestFile(".\\b\\a");
2780     CreateTestFile(".\\b\\b");
2781     CreateTestFile(".\\b\\c");
2782     CreateTestFile(".\\c\\a");
2783     CreateTestFile(".\\c\\b");
2784     CreateTestFile(".\\c\\c");
2785 
2786     SHGetDesktopFolder(&psf_desktop);
2787     hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2788     ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2789     hr = IShellFolder_BindToObject(psf_desktop, pidl_cwd, NULL, &IID_IShellFolder, (void**)&psf_current);
2790     ok(SUCCEEDED(hr), "BindToObject returned %x\n", hr);
2791     IShellFolder_Release(psf_desktop);
2792     ILFree(pidl_cwd);
2793 
2794     /* Generate ShellItems for the files */
2795     memset(&psi, 0, sizeof(psi));
2796     failed = FALSE;
2797     for(i = 0; i < 9; i++)
2798     {
2799         LPITEMIDLIST pidl_testfile = NULL;
2800 
2801         hr = IShellFolder_ParseDisplayName(psf_current, NULL, NULL, (LPWSTR)filesW[i],
2802                                            NULL, &pidl_testfile, NULL);
2803         ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2804         if(SUCCEEDED(hr))
2805         {
2806             hr = pSHCreateShellItem(NULL, NULL, pidl_testfile, &psi[i]);
2807             ok(hr == S_OK, "Got 0x%08x\n", hr);
2808             ILFree(pidl_testfile);
2809         }
2810         if(FAILED(hr)) failed = TRUE;
2811     }
2812     if(failed)
2813     {
2814         skip("Failed to create all shellitems.\n");
2815         goto cleanup;
2816     }
2817 
2818     /* Generate ShellItems for the folders */
2819     hr = IShellItem_GetParent(psi[0], &psi_a);
2820     ok(hr == S_OK, "Got 0x%08x\n", hr);
2821     if(FAILED(hr)) failed = TRUE;
2822     hr = IShellItem_GetParent(psi[3], &psi_b);
2823     ok(hr == S_OK, "Got 0x%08x\n", hr);
2824     if(FAILED(hr)) failed = TRUE;
2825     hr = IShellItem_GetParent(psi[6], &psi_c);
2826     ok(hr == S_OK, "Got 0x%08x\n", hr);
2827     if(FAILED(hr)) failed = TRUE;
2828 
2829     if(failed)
2830     {
2831         skip("Failed to create shellitems.\n");
2832         goto cleanup;
2833     }
2834 
2835     if(0)
2836     {
2837         /* Crashes on native (win7, winxp) */
2838         IShellItem_Compare(psi_a, NULL, 0, NULL);
2839         IShellItem_Compare(psi_a, psi_b, 0, NULL);
2840         IShellItem_Compare(psi_a, NULL, 0, &order);
2841     }
2842 
2843     /* Basics */
2844     for(i = 0; i < 9; i++)
2845     {
2846         hr = IShellItem_Compare(psi[i], psi[i], SICHINT_DISPLAY, &order);
2847         ok(hr == S_OK, "Got 0x%08x\n", hr);
2848         ok(order == 0, "Got order %d\n", order);
2849         hr = IShellItem_Compare(psi[i], psi[i], SICHINT_CANONICAL, &order);
2850         ok(hr == S_OK, "Got 0x%08x\n", hr);
2851         ok(order == 0, "Got order %d\n", order);
2852         hr = IShellItem_Compare(psi[i], psi[i], SICHINT_ALLFIELDS, &order);
2853         ok(hr == S_OK, "Got 0x%08x\n", hr);
2854         ok(order == 0, "Got order %d\n", order);
2855     }
2856 
2857     /* Order */
2858     /* a\b:a\a , a\b:a\c, a\b:a\b */
2859     hr = IShellItem_Compare(psi[1], psi[0], SICHINT_DISPLAY, &order);
2860     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2861     ok(order == 1, "Got order %d\n", order);
2862     hr = IShellItem_Compare(psi[1], psi[2], SICHINT_DISPLAY, &order);
2863     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2864     ok(order == -1, "Got order %d\n", order);
2865     hr = IShellItem_Compare(psi[1], psi[1], SICHINT_DISPLAY, &order);
2866     ok(hr == S_OK, "Got 0x%08x\n", hr);
2867     ok(order == 0, "Got order %d\n", order);
2868 
2869     /* b\b:a\b, b\b:c\b, b\b:c\b */
2870     hr = IShellItem_Compare(psi[4], psi[1], SICHINT_DISPLAY, &order);
2871     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2872     ok(order == 1, "Got order %d\n", order);
2873     hr = IShellItem_Compare(psi[4], psi[7], SICHINT_DISPLAY, &order);
2874     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2875     ok(order == -1, "Got order %d\n", order);
2876     hr = IShellItem_Compare(psi[4], psi[4], SICHINT_DISPLAY, &order);
2877     ok(hr == S_OK, "Got 0x%08x\n", hr);
2878     ok(order == 0, "Got order %d\n", order);
2879 
2880     /* b:a\a, b:a\c, b:a\b */
2881     hr = IShellItem_Compare(psi_b, psi[0], SICHINT_DISPLAY, &order);
2882     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2883     todo_wine ok(order == 1, "Got order %d\n", order);
2884     hr = IShellItem_Compare(psi_b, psi[2], SICHINT_DISPLAY, &order);
2885     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2886     todo_wine ok(order == 1, "Got order %d\n", order);
2887     hr = IShellItem_Compare(psi_b, psi[1], SICHINT_DISPLAY, &order);
2888     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2889     todo_wine ok(order == 1, "Got order %d\n", order);
2890 
2891     /* b:c\a, b:c\c, b:c\b */
2892     hr = IShellItem_Compare(psi_b, psi[6], SICHINT_DISPLAY, &order);
2893     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2894     ok(order == -1, "Got order %d\n", order);
2895     hr = IShellItem_Compare(psi_b, psi[8], SICHINT_DISPLAY, &order);
2896     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2897     ok(order == -1, "Got order %d\n", order);
2898     hr = IShellItem_Compare(psi_b, psi[7], SICHINT_DISPLAY, &order);
2899     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2900     ok(order == -1, "Got order %d\n", order);
2901 
2902     /* a\b:a\a , a\b:a\c, a\b:a\b */
2903     hr = IShellItem_Compare(psi[1], psi[0], SICHINT_CANONICAL, &order);
2904     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2905     ok(order == 1, "Got order %d\n", order);
2906     hr = IShellItem_Compare(psi[1], psi[2], SICHINT_CANONICAL, &order);
2907     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2908     ok(order == -1, "Got order %d\n", order);
2909     hr = IShellItem_Compare(psi[1], psi[1], SICHINT_CANONICAL, &order);
2910     ok(hr == S_OK, "Got 0x%08x\n", hr);
2911     ok(order == 0, "Got order %d\n", order);
2912 
2913     /* b\b:a\b, b\b:c\b, b\b:c\b */
2914     hr = IShellItem_Compare(psi[4], psi[1], SICHINT_CANONICAL, &order);
2915     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2916     ok(order == 1, "Got order %d\n", order);
2917     hr = IShellItem_Compare(psi[4], psi[7], SICHINT_CANONICAL, &order);
2918     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2919     ok(order == -1, "Got order %d\n", order);
2920     hr = IShellItem_Compare(psi[4], psi[4], SICHINT_CANONICAL, &order);
2921     ok(hr == S_OK, "Got 0x%08x\n", hr);
2922     ok(order == 0, "Got order %d\n", order);
2923 
2924     /* b:a\a, b:a\c, b:a\b */
2925     hr = IShellItem_Compare(psi_b, psi[0], SICHINT_CANONICAL, &order);
2926     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2927     todo_wine ok(order == 1, "Got order %d\n", order);
2928     hr = IShellItem_Compare(psi_b, psi[2], SICHINT_CANONICAL, &order);
2929     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2930     todo_wine ok(order == 1, "Got order %d\n", order);
2931     hr = IShellItem_Compare(psi_b, psi[1], SICHINT_CANONICAL, &order);
2932     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2933     todo_wine ok(order == 1, "Got order %d\n", order);
2934 
2935     /* b:c\a, b:c\c, b:c\b */
2936     hr = IShellItem_Compare(psi_b, psi[6], SICHINT_CANONICAL, &order);
2937     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2938     ok(order == -1, "Got order %d\n", order);
2939     hr = IShellItem_Compare(psi_b, psi[8], SICHINT_CANONICAL, &order);
2940     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2941     ok(order == -1, "Got order %d\n", order);
2942     hr = IShellItem_Compare(psi_b, psi[7], SICHINT_CANONICAL, &order);
2943     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2944     ok(order == -1, "Got order %d\n", order);
2945 
2946 cleanup:
2947     IShellFolder_Release(psf_current);
2948 
2949     DeleteFileA(".\\a\\a");
2950     DeleteFileA(".\\a\\b");
2951     DeleteFileA(".\\a\\c");
2952     DeleteFileA(".\\b\\a");
2953     DeleteFileA(".\\b\\b");
2954     DeleteFileA(".\\b\\c");
2955     DeleteFileA(".\\c\\a");
2956     DeleteFileA(".\\c\\b");
2957     DeleteFileA(".\\c\\c");
2958     RemoveDirectoryA(".\\a");
2959     RemoveDirectoryA(".\\b");
2960     RemoveDirectoryA(".\\c");
2961 
2962     if(psi_a) IShellItem_Release(psi_a);
2963     if(psi_b) IShellItem_Release(psi_b);
2964     if(psi_c) IShellItem_Release(psi_c);
2965 
2966     for(i = 0; i < 9; i++)
2967         if(psi[i]) IShellItem_Release(psi[i]);
2968 }
2969 
2970 /**************************************************************/
2971 /* IUnknown implementation for counting QueryInterface calls. */
2972 typedef struct {
2973     IUnknown IUnknown_iface;
2974     struct if_count {
2975         REFIID id;
2976         LONG count;
2977     } *ifaces;
2978     LONG unknown;
2979 } IUnknownImpl;
2980 
impl_from_IUnknown(IUnknown * iface)2981 static inline IUnknownImpl *impl_from_IUnknown(IUnknown *iface)
2982 {
2983     return CONTAINING_RECORD(iface, IUnknownImpl, IUnknown_iface);
2984 }
2985 
unk_fnQueryInterface(IUnknown * iunk,REFIID riid,void ** punk)2986 static HRESULT WINAPI unk_fnQueryInterface(IUnknown *iunk, REFIID riid, void** punk)
2987 {
2988     IUnknownImpl *This = impl_from_IUnknown(iunk);
2989     UINT i;
2990     BOOL found = FALSE;
2991     for(i = 0; This->ifaces[i].id != NULL; i++)
2992     {
2993         if(IsEqualIID(This->ifaces[i].id, riid))
2994         {
2995             This->ifaces[i].count++;
2996             found = TRUE;
2997             break;
2998         }
2999     }
3000     if(!found)
3001         This->unknown++;
3002     return E_NOINTERFACE;
3003 }
3004 
unk_fnAddRef(IUnknown * iunk)3005 static ULONG WINAPI unk_fnAddRef(IUnknown *iunk)
3006 {
3007     return 2;
3008 }
3009 
unk_fnRelease(IUnknown * iunk)3010 static ULONG WINAPI unk_fnRelease(IUnknown *iunk)
3011 {
3012     return 1;
3013 }
3014 
3015 static const IUnknownVtbl vt_IUnknown = {
3016     unk_fnQueryInterface,
3017     unk_fnAddRef,
3018     unk_fnRelease
3019 };
3020 
test_SHGetIDListFromObject(void)3021 static void test_SHGetIDListFromObject(void)
3022 {
3023     IUnknownImpl *punkimpl;
3024     IShellFolder *psfdesktop;
3025     IShellView *psv;
3026     LPITEMIDLIST pidl, pidl_desktop;
3027     HRESULT hres;
3028     UINT i;
3029     struct if_count ifaces[] =
3030         { {&IID_IPersistIDList, 0},
3031           {&IID_IPersistFolder2, 0},
3032           {&IID_IDataObject, 0},
3033           {&IID_IParentAndItem, 0},
3034           {&IID_IFolderView, 0},
3035           {NULL, 0} };
3036 
3037     if(!pSHGetIDListFromObject)
3038     {
3039         win_skip("SHGetIDListFromObject missing.\n");
3040         return;
3041     }
3042 
3043     if(0)
3044     {
3045         /* Crashes native */
3046         pSHGetIDListFromObject(NULL, NULL);
3047         pSHGetIDListFromObject((void*)0xDEADBEEF, NULL);
3048     }
3049 
3050     hres = pSHGetIDListFromObject(NULL, &pidl);
3051     ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3052 
3053     punkimpl = heap_alloc(sizeof(*punkimpl));
3054     punkimpl->IUnknown_iface.lpVtbl = &vt_IUnknown;
3055     punkimpl->ifaces = ifaces;
3056     punkimpl->unknown = 0;
3057 
3058     hres = pSHGetIDListFromObject(&punkimpl->IUnknown_iface, &pidl);
3059     ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3060     ok(ifaces[0].count, "interface not requested.\n");
3061     ok(ifaces[1].count, "interface not requested.\n");
3062     ok(ifaces[2].count, "interface not requested.\n");
3063     todo_wine
3064         ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3065            "interface not requested.\n");
3066     ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3067        "interface not requested.\n");
3068 
3069     ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3070     heap_free(punkimpl);
3071 
3072     pidl_desktop = NULL;
3073     SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3074     ok(pidl_desktop != NULL, "Failed to get desktop pidl.\n");
3075 
3076     SHGetDesktopFolder(&psfdesktop);
3077 
3078     /* Test IShellItem */
3079     if(pSHCreateShellItem)
3080     {
3081         IShellItem *shellitem;
3082         hres = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
3083         ok(hres == S_OK, "got 0x%08x\n", hres);
3084         if(SUCCEEDED(hres))
3085         {
3086             hres = pSHGetIDListFromObject((IUnknown*)shellitem, &pidl);
3087             ok(hres == S_OK, "got 0x%08x\n", hres);
3088             if(SUCCEEDED(hres))
3089             {
3090                 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3091                 ILFree(pidl);
3092             }
3093             IShellItem_Release(shellitem);
3094         }
3095     }
3096     else
3097         skip("no SHCreateShellItem.\n");
3098 
3099     /* Test IShellFolder */
3100     hres = pSHGetIDListFromObject((IUnknown*)psfdesktop, &pidl);
3101     ok(hres == S_OK, "got 0x%08x\n", hres);
3102     if(SUCCEEDED(hres))
3103     {
3104         ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3105         ILFree(pidl);
3106     }
3107 
3108     hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
3109     ok(hres == S_OK, "got 0x%08x\n", hres);
3110     if(SUCCEEDED(hres))
3111     {
3112         IEnumIDList *peidl;
3113         IDataObject *pdo;
3114         SHCONTF enum_flags;
3115 
3116         /* Test IFolderView */
3117         hres = pSHGetIDListFromObject((IUnknown*)psv, &pidl);
3118         ok(hres == S_OK, "got 0x%08x\n", hres);
3119         if(SUCCEEDED(hres))
3120         {
3121             ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3122             ILFree(pidl);
3123         }
3124 
3125         /* Test IDataObject */
3126         enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3127         hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
3128         ok(hres == S_OK, "got 0x%08x\n", hres);
3129         if(SUCCEEDED(hres))
3130         {
3131             LPITEMIDLIST apidl[5];
3132             UINT count = 0;
3133             for(count = 0; count < 5; count++)
3134                 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3135                     break;
3136 
3137             if(count)
3138             {
3139                 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
3140                                                   &IID_IDataObject, NULL, (void**)&pdo);
3141                 ok(hres == S_OK, "got 0x%08x\n", hres);
3142                 if(SUCCEEDED(hres))
3143                 {
3144                     pidl = (void*)0xDEADBEEF;
3145                     hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3146                     ok(hres == S_OK, "got 0x%08x\n", hres);
3147                     ok(pidl != NULL, "pidl is NULL.\n");
3148                     ok(ILIsEqual(pidl, apidl[0]), "pidl not equal.\n");
3149                     ILFree(pidl);
3150 
3151                     IDataObject_Release(pdo);
3152                 }
3153             }
3154             else
3155                 skip("No files found - skipping single-file test.\n");
3156 
3157             if(count > 1)
3158             {
3159                 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
3160                                                   &IID_IDataObject, NULL, (void**)&pdo);
3161                 ok(hres == S_OK, "got 0x%08x\n", hres);
3162                 if(SUCCEEDED(hres))
3163                 {
3164                     pidl = (void*)0xDEADBEEF;
3165                     hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3166                     ok(hres == E_NOINTERFACE || hres == E_FAIL /*Vista*/,
3167                        "got 0x%08x\n", hres);
3168                     ok(pidl == NULL, "pidl is not NULL.\n");
3169 
3170                     IDataObject_Release(pdo);
3171                 }
3172             }
3173             else
3174                 skip("zero or one file found - skipping multi-file test.\n");
3175 
3176             for(i = 0; i < count; i++)
3177                 ILFree(apidl[i]);
3178 
3179             IEnumIDList_Release(peidl);
3180         }
3181 
3182         IShellView_Release(psv);
3183     }
3184 
3185     IShellFolder_Release(psfdesktop);
3186     ILFree(pidl_desktop);
3187 }
3188 
test_SHGetItemFromObject(void)3189 static void test_SHGetItemFromObject(void)
3190 {
3191     IUnknownImpl *punkimpl;
3192     IShellFolder *psfdesktop;
3193     LPITEMIDLIST pidl;
3194     IShellItem *psi;
3195     IUnknown *punk;
3196     HRESULT hres;
3197     struct if_count ifaces[] =
3198         { {&IID_IPersistIDList, 0},
3199           {&IID_IPersistFolder2, 0},
3200           {&IID_IDataObject, 0},
3201           {&IID_IParentAndItem, 0},
3202           {&IID_IFolderView, 0},
3203           {NULL, 0} };
3204 
3205     if(!pSHGetItemFromObject)
3206     {
3207         skip("No SHGetItemFromObject.\n");
3208         return;
3209     }
3210 
3211     SHGetDesktopFolder(&psfdesktop);
3212 
3213     if(0)
3214     {
3215         /* Crashes with Windows 7 */
3216         pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IUnknown, NULL);
3217         pSHGetItemFromObject(NULL, &IID_IUnknown, NULL);
3218         pSHGetItemFromObject((IUnknown*)psfdesktop, NULL, (void**)&punk);
3219     }
3220 
3221     hres = pSHGetItemFromObject(NULL, &IID_IUnknown, (void**)&punk);
3222     ok(hres == E_NOINTERFACE, "Got 0x%08x\n", hres);
3223 
3224     punkimpl = heap_alloc(sizeof(*punkimpl));
3225     punkimpl->IUnknown_iface.lpVtbl = &vt_IUnknown;
3226     punkimpl->ifaces = ifaces;
3227     punkimpl->unknown = 0;
3228 
3229     /* The same as SHGetIDListFromObject */
3230     hres = pSHGetIDListFromObject(&punkimpl->IUnknown_iface, &pidl);
3231     ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3232     ok(ifaces[0].count, "interface not requested.\n");
3233     ok(ifaces[1].count, "interface not requested.\n");
3234     ok(ifaces[2].count, "interface not requested.\n");
3235     todo_wine
3236         ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3237            "interface not requested.\n");
3238     ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3239        "interface not requested.\n");
3240 
3241     ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3242     heap_free(punkimpl);
3243 
3244     /* Test IShellItem */
3245     hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IShellItem, (void**)&psi);
3246     ok(hres == S_OK, "Got 0x%08x\n", hres);
3247     if(SUCCEEDED(hres))
3248     {
3249         IShellItem *psi2;
3250         hres = pSHGetItemFromObject((IUnknown*)psi, &IID_IShellItem, (void**)&psi2);
3251         ok(hres == S_OK, "Got 0x%08x\n", hres);
3252         if(SUCCEEDED(hres))
3253         {
3254             todo_wine
3255                 ok(psi == psi2, "Different instances (%p != %p).\n", psi, psi2);
3256             IShellItem_Release(psi2);
3257         }
3258         IShellItem_Release(psi);
3259     }
3260 
3261     IShellFolder_Release(psfdesktop);
3262 }
3263 
test_SHCreateShellItemArray(void)3264 static void test_SHCreateShellItemArray(void)
3265 {
3266     IShellFolder *pdesktopsf, *psf;
3267     IShellItemArray *psia;
3268     IEnumIDList *peidl;
3269     HRESULT hr;
3270     WCHAR cTestDirW[MAX_PATH];
3271     LPITEMIDLIST pidl_testdir, pidl;
3272     static const WCHAR testdirW[] = {'t','e','s','t','d','i','r',0};
3273 
3274     if(!pSHCreateShellItemArray) {
3275         skip("No pSHCreateShellItemArray!\n");
3276         return;
3277     }
3278 
3279     if(0)
3280     {
3281         /* Crashes under native */
3282         pSHCreateShellItemArray(NULL, NULL, 0, NULL, NULL);
3283         pSHCreateShellItemArray(NULL, NULL, 1, NULL, NULL);
3284         pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, NULL);
3285         pSHCreateShellItemArray(pidl, NULL, 0, NULL, NULL);
3286     }
3287 
3288     hr = pSHCreateShellItemArray(NULL, NULL, 0, NULL, &psia);
3289     ok(hr == E_POINTER, "got 0x%08x\n", hr);
3290 
3291     SHGetDesktopFolder(&pdesktopsf);
3292     hr = pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, &psia);
3293     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3294 
3295     hr = pSHCreateShellItemArray(NULL, pdesktopsf, 1, NULL, &psia);
3296     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3297 
3298     SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
3299     hr = pSHCreateShellItemArray(pidl, NULL, 0, NULL, &psia);
3300     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3301     ILFree(pidl);
3302 
3303     GetCurrentDirectoryW(MAX_PATH, cTestDirW);
3304     myPathAddBackslashW(cTestDirW);
3305     lstrcatW(cTestDirW, testdirW);
3306 
3307     CreateFilesFolders();
3308 
3309     hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, cTestDirW, NULL, &pidl_testdir, 0);
3310     ok(hr == S_OK, "got 0x%08x\n", hr);
3311     if(SUCCEEDED(hr))
3312     {
3313         hr = IShellFolder_BindToObject(pdesktopsf, pidl_testdir, NULL, (REFIID)&IID_IShellFolder,
3314                                        (void**)&psf);
3315         ok(hr == S_OK, "Got 0x%08x\n", hr);
3316     }
3317     IShellFolder_Release(pdesktopsf);
3318 
3319     if(FAILED(hr))
3320     {
3321         skip("Failed to set up environment for SHCreateShellItemArray tests.\n");
3322         ILFree(pidl_testdir);
3323         Cleanup();
3324         return;
3325     }
3326 
3327     hr = IShellFolder_EnumObjects(psf, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &peidl);
3328     ok(hr == S_OK, "Got %08x\n", hr);
3329     if(SUCCEEDED(hr))
3330     {
3331         LPITEMIDLIST apidl[5];
3332         UINT done, numitems, i;
3333 
3334         for(done = 0; done < 5; done++)
3335             if(IEnumIDList_Next(peidl, 1, &apidl[done], NULL) != S_OK)
3336                 break;
3337         ok(done == 5, "Got %d pidls\n", done);
3338         IEnumIDList_Release(peidl);
3339 
3340         /* Create a ShellItemArray */
3341         hr = pSHCreateShellItemArray(NULL, psf, done, (LPCITEMIDLIST*)apidl, &psia);
3342         ok(hr == S_OK, "Got 0x%08x\n", hr);
3343         if(SUCCEEDED(hr))
3344         {
3345             IShellItem *psi;
3346 
3347             if(0)
3348             {
3349                 /* Crashes in Windows 7 */
3350                 IShellItemArray_GetCount(psia, NULL);
3351             }
3352 
3353             IShellItemArray_GetCount(psia, &numitems);
3354             ok(numitems == done, "Got %d, expected %d\n", numitems, done);
3355 
3356             hr = IShellItemArray_GetItemAt(psia, numitems, &psi);
3357             ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3358 
3359             /* Compare all the items */
3360             for(i = 0; i < numitems; i++)
3361             {
3362                 LPITEMIDLIST pidl_abs;
3363                 pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3364 
3365                 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3366                 ok(hr == S_OK, "(%d) Failed with 0x%08x\n", i, hr);
3367                 if(SUCCEEDED(hr))
3368                 {
3369                     hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3370                     ok(hr == S_OK, "Got 0x%08x\n", hr);
3371                     if(SUCCEEDED(hr))
3372                     {
3373                         ok(ILIsEqual(pidl_abs, pidl), "Pidl not equal.\n");
3374                         ILFree(pidl);
3375                     }
3376                     IShellItem_Release(psi);
3377                 }
3378                 ILFree(pidl_abs);
3379             }
3380             for(i = 0; i < done; i++)
3381                 ILFree(apidl[i]);
3382             IShellItemArray_Release(psia);
3383         }
3384     }
3385 
3386     /* SHCreateShellItemArrayFromShellItem */
3387     if(pSHCreateShellItemArrayFromShellItem)
3388     {
3389         IShellItem *psi;
3390 
3391         if(0)
3392         {
3393             /* Crashes under Windows 7 */
3394             pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, NULL);
3395             pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, (void**)&psia);
3396             pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, NULL);
3397         }
3398 
3399         hr = pSHCreateItemFromIDList(pidl_testdir, &IID_IShellItem, (void**)&psi);
3400         ok(hr == S_OK, "Got 0x%08x\n", hr);
3401         if(SUCCEEDED(hr))
3402         {
3403             hr = pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, (void**)&psia);
3404             ok(hr == S_OK, "Got 0x%08x\n", hr);
3405             if(SUCCEEDED(hr))
3406             {
3407                 IShellItem *psi2;
3408                 UINT count;
3409                 hr = IShellItemArray_GetCount(psia, &count);
3410                 ok(hr == S_OK, "Got 0x%08x\n", hr);
3411                 ok(count == 1, "Got count %d\n", count);
3412                 hr = IShellItemArray_GetItemAt(psia, 0, &psi2);
3413                 ok(hr == S_OK, "Got 0x%08x\n", hr);
3414                 todo_wine
3415                     ok(psi != psi2, "ShellItems are of the same instance.\n");
3416                 if(SUCCEEDED(hr))
3417                 {
3418                     LPITEMIDLIST pidl1, pidl2;
3419                     hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl1);
3420                     ok(hr == S_OK, "Got 0x%08x\n", hr);
3421                     ok(pidl1 != NULL, "pidl1 was null.\n");
3422                     hr = pSHGetIDListFromObject((IUnknown*)psi2, &pidl2);
3423                     ok(hr == S_OK, "Got 0x%08x\n", hr);
3424                     ok(pidl2 != NULL, "pidl2 was null.\n");
3425                     ok(ILIsEqual(pidl1, pidl2), "pidls not equal.\n");
3426                     ILFree(pidl1);
3427                     ILFree(pidl2);
3428                     IShellItem_Release(psi2);
3429                 }
3430                 hr = IShellItemArray_GetItemAt(psia, 1, &psi2);
3431                 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3432                 IShellItemArray_Release(psia);
3433             }
3434             IShellItem_Release(psi);
3435         }
3436     }
3437     else
3438         skip("No SHCreateShellItemArrayFromShellItem.\n");
3439 
3440     if(pSHCreateShellItemArrayFromDataObject)
3441     {
3442         IShellView *psv;
3443 
3444         if(0)
3445         {
3446             /* Crashes under Windows 7 */
3447             pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, NULL);
3448         }
3449         hr = pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, (void**)&psia);
3450         ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3451 
3452         hr = IShellFolder_CreateViewObject(psf, NULL, &IID_IShellView, (void**)&psv);
3453         ok(hr == S_OK, "got 0x%08x\n", hr);
3454         if(SUCCEEDED(hr))
3455         {
3456             IEnumIDList *peidl;
3457             IDataObject *pdo;
3458             SHCONTF enum_flags;
3459 
3460             enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3461             hr = IShellFolder_EnumObjects(psf, NULL, enum_flags, &peidl);
3462             ok(hr == S_OK, "got 0x%08x\n", hr);
3463             if(SUCCEEDED(hr))
3464             {
3465                 LPITEMIDLIST apidl[5];
3466                 UINT count, i;
3467 
3468                 for(count = 0; count < 5; count++)
3469                     if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3470                         break;
3471                 ok(count == 5, "Got %d\n", count);
3472 
3473                 if(count)
3474                 {
3475                     hr = IShellFolder_GetUIObjectOf(psf, NULL, count, (LPCITEMIDLIST*)apidl,
3476                                                     &IID_IDataObject, NULL, (void**)&pdo);
3477                     ok(hr == S_OK, "Got 0x%08x\n", hr);
3478                     if(SUCCEEDED(hr))
3479                     {
3480                         hr = pSHCreateShellItemArrayFromDataObject(pdo, &IID_IShellItemArray,
3481                                                                    (void**)&psia);
3482                         ok(hr == S_OK, "Got 0x%08x\n", hr);
3483                         if(SUCCEEDED(hr))
3484                         {
3485                             UINT count_sia, i;
3486                             hr = IShellItemArray_GetCount(psia, &count_sia);
3487                             ok(hr == S_OK, "Got 0x%08x\n", hr);
3488                             ok(count_sia == count, "Counts differ (%d, %d)\n", count, count_sia);
3489                             for(i = 0; i < count_sia; i++)
3490                             {
3491                                 LPITEMIDLIST pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3492                                 IShellItem *psi;
3493                                 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3494                                 ok(hr == S_OK, "Got 0x%08x\n", hr);
3495                                 if(SUCCEEDED(hr))
3496                                 {
3497                                     LPITEMIDLIST pidl;
3498                                     hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3499                                     ok(hr == S_OK, "Got 0x%08x\n", hr);
3500                                     ok(pidl != NULL, "pidl as NULL.\n");
3501                                     ok(ILIsEqual(pidl, pidl_abs), "pidls differ.\n");
3502                                     ILFree(pidl);
3503                                     IShellItem_Release(psi);
3504                                 }
3505                                 ILFree(pidl_abs);
3506                             }
3507 
3508                             IShellItemArray_Release(psia);
3509                         }
3510 
3511                         IDataObject_Release(pdo);
3512                     }
3513                     for(i = 0; i < count; i++)
3514                         ILFree(apidl[i]);
3515                 }
3516                 else
3517                     skip("No files found - skipping test.\n");
3518 
3519                 IEnumIDList_Release(peidl);
3520             }
3521             IShellView_Release(psv);
3522         }
3523     }
3524     else
3525         skip("No SHCreateShellItemArrayFromDataObject.\n");
3526 
3527     if(pSHCreateShellItemArrayFromIDLists)
3528     {
3529         WCHAR test1W[] = {'t','e','s','t','1','.','t','x','t',0};
3530         WCHAR test1pathW[MAX_PATH];
3531         LPITEMIDLIST pidltest1;
3532         LPCITEMIDLIST pidl_array[2];
3533 
3534         if(0)
3535         {
3536             /* Crashes */
3537             hr = pSHCreateShellItemArrayFromIDLists(0, NULL, NULL);
3538         }
3539 
3540         psia = (void*)0xdeadbeef;
3541         hr = pSHCreateShellItemArrayFromIDLists(0, NULL, &psia);
3542         ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3543         ok(psia == NULL, "Got %p\n", psia);
3544 
3545         psia = (void*)0xdeadbeef;
3546         hr = pSHCreateShellItemArrayFromIDLists(0, pidl_array, &psia);
3547         ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3548         ok(psia == NULL, "Got %p\n", psia);
3549 
3550         psia = (void*)0xdeadbeef;
3551         pidl_array[0] = NULL;
3552         hr = pSHCreateShellItemArrayFromIDLists(1, pidl_array, &psia);
3553         todo_wine ok(hr == E_OUTOFMEMORY, "Got 0x%08x\n", hr);
3554         ok(psia == NULL, "Got %p\n", psia);
3555 
3556         psia = (void*)0xdeadbeef;
3557         pidl_array[0] = pidl_testdir;
3558         pidl_array[1] = NULL;
3559         hr = pSHCreateShellItemArrayFromIDLists(2, pidl_array, &psia);
3560         todo_wine ok(hr == S_OK || broken(hr == E_INVALIDARG) /* Vista */, "Got 0x%08x\n", hr);
3561         todo_wine ok(psia != NULL || broken(psia == NULL) /* Vista */, "Got %p\n", psia);
3562         if(SUCCEEDED(hr))
3563         {
3564             IShellItem *psi;
3565             UINT count = 0;
3566 
3567             hr = IShellItemArray_GetCount(psia, &count);
3568             ok(hr == S_OK, "Got 0x%08x\n", hr);
3569             ok(count == 2, "Got %d\n", count);
3570 
3571             hr = IShellItemArray_GetItemAt(psia, 0, &psi);
3572             ok(hr == S_OK, "Got 0x%08x\n", hr);
3573             if(SUCCEEDED(hr))
3574             {
3575                 LPWSTR path;
3576                 hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3577                 ok(hr == S_OK, "Got 0x%08x\n", hr);
3578                 ok(!lstrcmpW(path, cTestDirW), "Got %s\n", wine_dbgstr_w(path));
3579                 if(SUCCEEDED(hr))
3580                     CoTaskMemFree(path);
3581 
3582                 IShellItem_Release(psi);
3583             }
3584 
3585             hr = IShellItemArray_GetItemAt(psia, 1, &psi);
3586             ok(hr == S_OK, "Got 0x%08x\n", hr);
3587             if(SUCCEEDED(hr))
3588             {
3589                 LPWSTR path;
3590                 WCHAR desktoppath[MAX_PATH];
3591                 BOOL result;
3592 
3593                 result = SHGetSpecialFolderPathW(NULL, desktoppath, CSIDL_DESKTOPDIRECTORY, FALSE);
3594                 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
3595 
3596                 hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3597                 ok(hr == S_OK, "Got 0x%08x\n", hr);
3598                 ok(!lstrcmpW(path, desktoppath), "Got %s\n", wine_dbgstr_w(path));
3599                 if(SUCCEEDED(hr))
3600                     CoTaskMemFree(path);
3601 
3602                 IShellItem_Release(psi);
3603             }
3604 
3605 
3606             IShellItemArray_Release(psia);
3607         }
3608 
3609 
3610         /* Single pidl */
3611         psia = (void*)0xdeadbeef;
3612         pidl_array[0] = pidl_testdir;
3613         hr = pSHCreateShellItemArrayFromIDLists(1, pidl_array, &psia);
3614         ok(hr == S_OK, "Got 0x%08x\n", hr);
3615         if(SUCCEEDED(hr))
3616         {
3617             IShellItem *psi;
3618             UINT count = 0;
3619 
3620             hr = IShellItemArray_GetCount(psia, &count);
3621             ok(hr == S_OK, "Got 0x%08x\n", hr);
3622             ok(count == 1, "Got %d\n", count);
3623 
3624             hr = IShellItemArray_GetItemAt(psia, 0, &psi);
3625             ok(hr == S_OK, "Got 0x%08x\n", hr);
3626             if(SUCCEEDED(hr))
3627             {
3628                 LPWSTR path;
3629                 hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3630                 ok(hr == S_OK, "Got 0x%08x\n", hr);
3631                 ok(!lstrcmpW(path, cTestDirW), "Got %s\n", wine_dbgstr_w(path));
3632                 if(SUCCEEDED(hr))
3633                     CoTaskMemFree(path);
3634 
3635                 IShellItem_Release(psi);
3636             }
3637 
3638             IShellItemArray_Release(psia);
3639         }
3640 
3641 
3642         lstrcpyW(test1pathW, cTestDirW);
3643         myPathAddBackslashW(test1pathW);
3644         lstrcatW(test1pathW, test1W);
3645 
3646         SHGetDesktopFolder(&pdesktopsf);
3647 
3648         hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, test1pathW, NULL, &pidltest1, NULL);
3649         ok(hr == S_OK, "Got 0x%08x\n", hr);
3650         if(SUCCEEDED(hr))
3651         {
3652             psia = (void*)0xdeadbeef;
3653             pidl_array[0] = pidl_testdir;
3654             pidl_array[1] = pidltest1;
3655             hr = pSHCreateShellItemArrayFromIDLists(2, pidl_array, &psia);
3656             ok(hr == S_OK, "Got 0x%08x\n", hr);
3657             if(SUCCEEDED(hr))
3658             {
3659                 IShellItem *psi;
3660                 UINT count = 0;
3661 
3662                 hr = IShellItemArray_GetCount(psia, &count);
3663                 ok(hr == S_OK, "Got 0x%08x\n", hr);
3664                 ok(count == 2, "Got %d\n", count);
3665 
3666                 hr = IShellItemArray_GetItemAt(psia, 0, &psi);
3667                 ok(hr == S_OK, "Got 0x%08x\n", hr);
3668                 if(SUCCEEDED(hr))
3669                 {
3670                     LPWSTR path;
3671                     hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3672                     ok(hr == S_OK, "Got 0x%08x\n", hr);
3673                     ok(!lstrcmpW(path, cTestDirW), "Got %s\n", wine_dbgstr_w(path));
3674                     if(SUCCEEDED(hr))
3675                         CoTaskMemFree(path);
3676 
3677                     IShellItem_Release(psi);
3678                 }
3679 
3680                 hr = IShellItemArray_GetItemAt(psia, 1, &psi);
3681                 ok(hr == S_OK, "Got 0x%08x\n", hr);
3682                 if(SUCCEEDED(hr))
3683                 {
3684                     LPWSTR path;
3685                     hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3686                     ok(hr == S_OK, "Got 0x%08x\n", hr);
3687                     ok(!lstrcmpW(path, test1pathW), "Got %s\n", wine_dbgstr_w(path));
3688                     if(SUCCEEDED(hr))
3689                         CoTaskMemFree(path);
3690 
3691                     IShellItem_Release(psi);
3692                 }
3693 
3694 
3695                 IShellItemArray_Release(psia);
3696             }
3697 
3698             ILFree(pidltest1);
3699         }
3700 
3701         IShellFolder_Release(pdesktopsf);
3702     }
3703     else
3704         skip("No SHCreateShellItemArrayFromIDLists.\n");
3705 
3706     IShellFolder_Release(psf);
3707     ILFree(pidl_testdir);
3708     Cleanup();
3709 }
3710 
test_ShellItemArrayEnumItems(void)3711 static void test_ShellItemArrayEnumItems(void)
3712 {
3713     IShellFolder *pdesktopsf, *psf;
3714     IEnumIDList *peidl;
3715     WCHAR cTestDirW[MAX_PATH];
3716     HRESULT hr;
3717     LPITEMIDLIST pidl_testdir;
3718     static const WCHAR testdirW[] = {'t','e','s','t','d','i','r',0};
3719 
3720     if(!pSHCreateShellItemArray)
3721     {
3722         win_skip("No SHCreateShellItemArray, skipping test...\n");
3723         return;
3724     }
3725 
3726     CreateFilesFolders();
3727 
3728     SHGetDesktopFolder(&pdesktopsf);
3729 
3730     GetCurrentDirectoryW(MAX_PATH, cTestDirW);
3731     myPathAddBackslashW(cTestDirW);
3732     lstrcatW(cTestDirW, testdirW);
3733 
3734     hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, cTestDirW, NULL, &pidl_testdir, 0);
3735     ok(hr == S_OK, "got 0x%08x\n", hr);
3736     if(SUCCEEDED(hr))
3737     {
3738         hr = IShellFolder_BindToObject(pdesktopsf, pidl_testdir, NULL, (REFIID)&IID_IShellFolder,
3739                                        (void**)&psf);
3740         ok(hr == S_OK, "Got 0x%08x\n", hr);
3741         ILFree(pidl_testdir);
3742     }
3743     IShellFolder_Release(pdesktopsf);
3744     if (FAILED(hr)) return;
3745 
3746     hr = IShellFolder_EnumObjects(psf, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &peidl);
3747     ok(hr == S_OK, "Got %08x\n", hr);
3748     if(SUCCEEDED(hr))
3749     {
3750         IShellItemArray *psia;
3751         LPITEMIDLIST apidl[5];
3752         UINT done, numitems, i;
3753 
3754         for(done = 0; done < 5; done++)
3755             if(IEnumIDList_Next(peidl, 1, &apidl[done], NULL) != S_OK)
3756                 break;
3757         ok(done == 5, "Got %d pidls\n", done);
3758         IEnumIDList_Release(peidl);
3759 
3760         /* Create a ShellItemArray */
3761         hr = pSHCreateShellItemArray(NULL, psf, done, (LPCITEMIDLIST*)apidl, &psia);
3762         ok(hr == S_OK, "Got 0x%08x\n", hr);
3763         if(SUCCEEDED(hr))
3764         {
3765             IEnumShellItems *iesi;
3766             IShellItem *my_array[10];
3767             ULONG fetched;
3768 
3769             IShellItemArray_GetCount(psia, &numitems);
3770             ok(numitems == done, "Got %d, expected %d\n", numitems, done);
3771 
3772             iesi = NULL;
3773             hr = IShellItemArray_EnumItems(psia, &iesi);
3774             ok(hr == S_OK, "Got 0x%08x\n", hr);
3775             ok(iesi != NULL, "Got NULL\n");
3776             if(SUCCEEDED(hr))
3777             {
3778                 IEnumShellItems *iesi2;
3779 
3780                 /* This should fail according to the documentation and Win7+ */
3781                 for(i = 0; i < 10; i++) my_array[i] = (void*)0xdeadbeef;
3782                 hr = IEnumShellItems_Next(iesi, 2, my_array, NULL);
3783                 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* Vista */, "Got 0x%08x\n", hr);
3784                 for(i = 0; i < 2; i++)
3785                 {
3786                     ok(my_array[i] == (void*)0xdeadbeef ||
3787                        broken(my_array[i] != (void*)0xdeadbeef && my_array[i] != NULL), /* Vista */
3788                        "Got %p (%d)\n", my_array[i], i);
3789 
3790                     if(my_array[i] != (void*)0xdeadbeef)
3791                         IShellItem_Release(my_array[i]);
3792                 }
3793                 ok(my_array[2] == (void*)0xdeadbeef, "Got %p\n", my_array[2]);
3794 
3795                 IEnumShellItems_Reset(iesi);
3796                 for(i = 0; i < 10; i++) my_array[i] = (void*)0xdeadbeef;
3797                 hr = IEnumShellItems_Next(iesi, 1, my_array, NULL);
3798                 ok(hr == S_OK, "Got 0x%08x\n", hr);
3799                 ok(my_array[0] != NULL && my_array[0] != (void*)0xdeadbeef, "Got %p\n", my_array[0]);
3800                 if(my_array[0] != NULL && my_array[0] != (void*)0xdeadbeef)
3801                     IShellItem_Release(my_array[0]);
3802                 ok(my_array[1] == (void*)0xdeadbeef, "Got %p\n", my_array[1]);
3803 
3804                 IEnumShellItems_Reset(iesi);
3805                 fetched = 0;
3806                 for(i = 0; i < 10; i++) my_array[i] = (void*)0xdeadbeef;
3807                 hr = IEnumShellItems_Next(iesi, numitems, my_array, &fetched);
3808                 ok(hr == S_OK, "Got 0x%08x\n", hr);
3809                 ok(fetched == numitems, "Got %d\n", fetched);
3810                 for(i = 0;i < numitems; i++)
3811                 {
3812                     ok(my_array[i] != NULL && my_array[i] != (void*)0xdeadbeef,
3813                        "Got %p at %d\n", my_array[i], i);
3814 
3815                     if(my_array[i] != NULL && my_array[i] != (void*)0xdeadbeef)
3816                         IShellItem_Release(my_array[i]);
3817                 }
3818                 ok(my_array[i] == (void*)0xdeadbeef, "Got %p\n", my_array[i]);
3819 
3820                 /* Compare all the items */
3821                 IEnumShellItems_Reset(iesi);
3822                 for(i = 0; i < numitems; i++)
3823                 {
3824                     IShellItem *psi;
3825                     int order;
3826 
3827                     hr = IShellItemArray_GetItemAt(psia, i, &psi);
3828                     ok(hr == S_OK, "Got 0x%08x\n", hr);
3829                     hr = IEnumShellItems_Next(iesi, 1, my_array, &fetched);
3830                     ok(hr == S_OK, "Got 0x%08x\n", hr);
3831                     ok(fetched == 1, "Got %d\n", fetched);
3832 
3833                     hr = IShellItem_Compare(psi, my_array[0], 0, &order);
3834                     ok(hr == S_OK, "Got 0x%08x\n", hr);
3835                     ok(order == 0, "Got %d\n", order);
3836 
3837                     IShellItem_Release(psi);
3838                     IShellItem_Release(my_array[0]);
3839                 }
3840 
3841                 my_array[0] = (void*)0xdeadbeef;
3842                 hr = IEnumShellItems_Next(iesi, 1, my_array, &fetched);
3843                 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3844                 ok(fetched == 0, "Got %d\n", fetched);
3845                 ok(my_array[0] == (void*)0xdeadbeef, "Got %p\n", my_array[0]);
3846 
3847                 /* Cloning not implemented anywhere */
3848                 iesi2 = (void*)0xdeadbeef;
3849                 hr = IEnumShellItems_Clone(iesi, &iesi2);
3850                 ok(hr == E_NOTIMPL, "Got 0x%08x\n", hr);
3851                 ok(iesi2 == NULL || broken(iesi2 == (void*)0xdeadbeef) /* Vista */, "Got %p\n", iesi2);
3852 
3853                 IEnumShellItems_Release(iesi);
3854             }
3855 
3856             IShellItemArray_Release(psia);
3857         }
3858 
3859         for(i = 0; i < done; i++)
3860             ILFree(apidl[i]);
3861     }
3862 
3863     IShellFolder_Release(psf);
3864 }
3865 
3866 
test_ShellItemBindToHandler(void)3867 static void test_ShellItemBindToHandler(void)
3868 {
3869     IShellItem *psi;
3870     LPITEMIDLIST pidl_desktop;
3871     HRESULT hr;
3872 
3873     if(!pSHCreateShellItem)
3874     {
3875         skip("SHCreateShellItem missing.\n");
3876         return;
3877     }
3878 
3879     hr = SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3880     ok(hr == S_OK, "Got 0x%08x\n", hr);
3881     if(SUCCEEDED(hr))
3882     {
3883         hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
3884         ok(hr == S_OK, "Got 0x%08x\n", hr);
3885     }
3886     if(SUCCEEDED(hr))
3887     {
3888         IPersistFolder2 *ppf2;
3889         IUnknown *punk;
3890 
3891         if(0)
3892         {
3893             /* Crashes under Windows 7 */
3894             IShellItem_BindToHandler(psi, NULL, NULL, NULL, NULL);
3895             IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, NULL);
3896         }
3897         hr = IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, (void**)&punk);
3898         ok(hr == MK_E_NOOBJECT, "Got 0x%08x\n", hr);
3899 
3900         /* BHID_SFObject */
3901         hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IShellFolder, (void**)&punk);
3902         ok(hr == S_OK, "Got 0x%08x\n", hr);
3903         if(SUCCEEDED(hr)) IUnknown_Release(punk);
3904         hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IPersistFolder2, (void**)&ppf2);
3905         ok(hr == S_OK, "Got 0x%08x\n", hr);
3906         if(SUCCEEDED(hr))
3907         {
3908             LPITEMIDLIST pidl_tmp;
3909             hr = IPersistFolder2_GetCurFolder(ppf2, &pidl_tmp);
3910             ok(hr == S_OK, "Got 0x%08x\n", hr);
3911             if(SUCCEEDED(hr))
3912             {
3913                 ok(ILIsEqual(pidl_desktop, pidl_tmp), "Pidl not equal (%p, %p)\n", pidl_desktop, pidl_tmp);
3914                 ILFree(pidl_tmp);
3915             }
3916             IPersistFolder2_Release(ppf2);
3917         }
3918 
3919         /* BHID_SFUIObject */
3920         hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IDataObject, (void**)&punk);
3921         ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3922         if(SUCCEEDED(hr)) IUnknown_Release(punk);
3923         hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IContextMenu, (void**)&punk);
3924         ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3925         if(SUCCEEDED(hr)) IUnknown_Release(punk);
3926 
3927         /* BHID_DataObject */
3928         hr = IShellItem_BindToHandler(psi, NULL, &BHID_DataObject, &IID_IDataObject, (void**)&punk);
3929         ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3930         if(SUCCEEDED(hr)) IUnknown_Release(punk);
3931 
3932         todo_wine
3933         {
3934             /* BHID_SFViewObject */
3935             hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellView, (void**)&punk);
3936             ok(hr == S_OK, "Got 0x%08x\n", hr);
3937             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3938             hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellFolderView, (void**)&punk);
3939             ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3940             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3941 
3942             /* BHID_Storage */
3943             hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IStream, (void**)&punk);
3944             ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3945             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3946             hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IUnknown, (void**)&punk);
3947             ok(hr == S_OK, "Got 0x%08x\n", hr);
3948             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3949 
3950             /* BHID_Stream */
3951             hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IStream, (void**)&punk);
3952             ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3953             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3954             hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IUnknown, (void**)&punk);
3955             ok(hr == S_OK, "Got 0x%08x\n", hr);
3956             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3957 
3958             /* BHID_StorageEnum */
3959             hr = IShellItem_BindToHandler(psi, NULL, &BHID_StorageEnum, &IID_IEnumShellItems, (void**)&punk);
3960             ok(hr == S_OK, "Got 0x%08x\n", hr);
3961             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3962 
3963             /* BHID_Transfer
3964                ITransferSource and ITransferDestination are accessible starting from Vista, IUnknown is
3965                supported starting from Win8. */
3966             hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_ITransferSource, (void**)&punk);
3967             ok(hr == S_OK || broken(FAILED(hr)) /* pre-Vista */, "Got 0x%08x\n", hr);
3968             if(SUCCEEDED(hr))
3969             {
3970                 IUnknown_Release(punk);
3971 
3972                 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_ITransferDestination, (void**)&punk);
3973                 ok(hr == S_OK, "Got 0x%08x\n", hr);
3974                 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3975 
3976                 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_IUnknown, (void**)&punk);
3977                 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* pre-Win8 */, "Got 0x%08x\n", hr);
3978                 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3979             }
3980 
3981             /* BHID_EnumItems */
3982             hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumItems, &IID_IEnumShellItems, (void**)&punk);
3983             ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3984             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3985 
3986             /* BHID_Filter */
3987             hr = IShellItem_BindToHandler(psi, NULL, &BHID_Filter, &IID_IUnknown, (void**)&punk);
3988             ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3989             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3990 
3991             /* BHID_LinkTargetItem */
3992             hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IShellItem, (void**)&punk);
3993             ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3994             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3995             hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IUnknown, (void**)&punk);
3996             ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3997             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3998 
3999             /* BHID_PropertyStore */
4000             hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStore, (void**)&punk);
4001             ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4002             if(SUCCEEDED(hr)) IUnknown_Release(punk);
4003             hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStoreFactory, (void**)&punk);
4004             ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4005             if(SUCCEEDED(hr)) IUnknown_Release(punk);
4006 
4007             /* BHID_ThumbnailHandler */
4008             hr = IShellItem_BindToHandler(psi, NULL, &BHID_ThumbnailHandler, &IID_IUnknown, (void**)&punk);
4009             ok(hr == E_INVALIDARG || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4010             if(SUCCEEDED(hr)) IUnknown_Release(punk);
4011 
4012             /* BHID_AssociationArray */
4013             hr = IShellItem_BindToHandler(psi, NULL, &BHID_AssociationArray, &IID_IQueryAssociations, (void**)&punk);
4014             ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4015             if(SUCCEEDED(hr)) IUnknown_Release(punk);
4016 
4017             /* BHID_EnumAssocHandlers */
4018             hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumAssocHandlers, &IID_IUnknown, (void**)&punk);
4019             ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4020             if(SUCCEEDED(hr)) IUnknown_Release(punk);
4021         }
4022 
4023         IShellItem_Release(psi);
4024     }
4025     else
4026         skip("Failed to create ShellItem.\n");
4027 
4028     ILFree(pidl_desktop);
4029 }
4030 
test_ShellItemGetAttributes(void)4031 static void test_ShellItemGetAttributes(void)
4032 {
4033     IShellItem *psi, *psi_folder1, *psi_file1;
4034     IShellFolder *pdesktopsf;
4035     LPITEMIDLIST pidl_desktop, pidl;
4036     SFGAOF sfgao;
4037     HRESULT hr;
4038     WCHAR curdirW[MAX_PATH];
4039     WCHAR buf[MAX_PATH];
4040     static const WCHAR testdir1W[] = {'t','e','s','t','d','i','r',0};
4041     static const WCHAR testfile1W[] = {'t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
4042 
4043     if(!pSHCreateShellItem)
4044     {
4045         skip("SHCreateShellItem missing.\n");
4046         return;
4047     }
4048 
4049     hr = SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
4050     ok(hr == S_OK, "Got 0x%08x\n", hr);
4051     if(SUCCEEDED(hr))
4052     {
4053         hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
4054         ok(hr == S_OK, "Got 0x%08x\n", hr);
4055         ILFree(pidl_desktop);
4056     }
4057     if(FAILED(hr))
4058     {
4059         skip("Skipping tests.\n");
4060         return;
4061     }
4062 
4063     if(0)
4064     {
4065         /* Crashes on native (Win 7) */
4066         IShellItem_GetAttributes(psi, 0, NULL);
4067     }
4068 
4069     /* Test GetAttributes on the desktop folder. */
4070     sfgao = 0xdeadbeef;
4071     hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER, &sfgao);
4072     ok(hr == S_OK || broken(hr == E_FAIL) /* <Vista */, "Got 0x%08x\n", hr);
4073     ok(sfgao == SFGAO_FOLDER || broken(sfgao == 0) /* <Vista */, "Got 0x%08x\n", sfgao);
4074 
4075     IShellItem_Release(psi);
4076 
4077     CreateFilesFolders();
4078 
4079     SHGetDesktopFolder(&pdesktopsf);
4080 
4081     GetCurrentDirectoryW(MAX_PATH, curdirW);
4082     myPathAddBackslashW(curdirW);
4083 
4084     lstrcpyW(buf, curdirW);
4085     lstrcatW(buf, testdir1W);
4086     hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, buf, NULL, &pidl, NULL);
4087     ok(hr == S_OK, "got 0x%08x\n", hr);
4088     hr = pSHCreateShellItem(NULL, NULL, pidl, &psi_folder1);
4089     ok(hr == S_OK, "Got 0x%08x\n", sfgao);
4090     ILFree(pidl);
4091 
4092     lstrcpyW(buf, curdirW);
4093     lstrcatW(buf, testfile1W);
4094     hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, buf, NULL, &pidl, NULL);
4095     ok(hr == S_OK, "got 0x%08x\n", hr);
4096     hr = pSHCreateShellItem(NULL, NULL, pidl, &psi_file1);
4097     ok(hr == S_OK, "Got 0x%08x\n", sfgao);
4098     ILFree(pidl);
4099 
4100     IShellFolder_Release(pdesktopsf);
4101 
4102     sfgao = 0xdeadbeef;
4103     hr = IShellItem_GetAttributes(psi_folder1, 0, &sfgao);
4104     ok(hr == S_OK, "Got 0x%08x\n", hr);
4105     ok(sfgao == 0, "Got 0x%08x\n", sfgao);
4106 
4107     sfgao = 0xdeadbeef;
4108     hr = IShellItem_GetAttributes(psi_folder1, SFGAO_FOLDER, &sfgao);
4109     ok(hr == S_OK, "Got 0x%08x\n", hr);
4110     ok(sfgao == SFGAO_FOLDER, "Got 0x%08x\n", sfgao);
4111 
4112     sfgao = 0xdeadbeef;
4113     hr = IShellItem_GetAttributes(psi_file1, SFGAO_FOLDER, &sfgao);
4114     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
4115     ok(sfgao == 0, "Got 0x%08x\n", sfgao);
4116 
4117     IShellItem_Release(psi_folder1);
4118     IShellItem_Release(psi_file1);
4119 
4120     Cleanup();
4121 }
4122 
test_ShellItemArrayGetAttributes(void)4123 static void test_ShellItemArrayGetAttributes(void)
4124 {
4125     IShellItemArray *psia_files, *psia_folders1, *psia_folders2, *psia_all;
4126     IShellFolder *pdesktopsf;
4127     LPCITEMIDLIST pidl_array[5];
4128     SFGAOF attr;
4129     HRESULT hr;
4130     WCHAR curdirW[MAX_PATH];
4131     WCHAR buf[MAX_PATH];
4132     UINT i;
4133     static const WCHAR testdir1W[] = {'t','e','s','t','d','i','r',0};
4134     static const WCHAR testdir2W[] = {'t','e','s','t','d','i','r','\\','t','e','s','t','d','i','r','2',0};
4135     static const WCHAR testdir3W[] = {'t','e','s','t','d','i','r','\\','t','e','s','t','d','i','r','3',0};
4136     static const WCHAR testfile1W[] = {'t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
4137     static const WCHAR testfile2W[] = {'t','e','s','t','d','i','r','\\','t','e','s','t','2','.','t','x','t',0};
4138     static const WCHAR *testfilesW[5] = { testdir1W, testdir2W, testdir3W, testfile1W, testfile2W };
4139 
4140     if(!pSHCreateShellItemArrayFromShellItem)
4141     {
4142         win_skip("No SHCreateShellItemArrayFromShellItem, skipping test...\n");
4143         return;
4144     }
4145 
4146     CreateFilesFolders();
4147     CreateDirectoryA(".\\testdir\\testdir3", NULL);
4148 
4149     SHGetDesktopFolder(&pdesktopsf);
4150 
4151     GetCurrentDirectoryW(MAX_PATH, curdirW);
4152     myPathAddBackslashW(curdirW);
4153 
4154     for(i = 0; i < 5; i++)
4155     {
4156         lstrcpyW(buf, curdirW);
4157         lstrcatW(buf, testfilesW[i]);
4158         hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, buf, NULL, (LPITEMIDLIST*)&pidl_array[i], NULL);
4159         ok(hr == S_OK, "got 0x%08x\n", hr);
4160     }
4161     IShellFolder_Release(pdesktopsf);
4162 
4163     hr = pSHCreateShellItemArrayFromIDLists(2, pidl_array, &psia_folders1);
4164     ok(hr == S_OK, "got 0x%08x\n", hr);
4165     hr = pSHCreateShellItemArrayFromIDLists(2, &pidl_array[1], &psia_folders2);
4166     ok(hr == S_OK, "got 0x%08x\n", hr);
4167     hr = pSHCreateShellItemArrayFromIDLists(2, &pidl_array[3], &psia_files);
4168     ok(hr == S_OK, "got 0x%08x\n", hr);
4169     hr = pSHCreateShellItemArrayFromIDLists(4, &pidl_array[1], &psia_all); /* All except the first */
4170     ok(hr == S_OK, "got 0x%08x\n", hr);
4171 
4172     for(i = 0; i < 5; i++)
4173         ILFree((LPITEMIDLIST)pidl_array[i]);
4174 
4175     /* [testfolder/, testfolder/testfolder2] seems to break in Vista */
4176     attr = 0xdeadbeef;
4177     hr = IShellItemArray_GetAttributes(psia_folders1, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attr);
4178     ok(hr == S_OK || broken(hr == E_UNEXPECTED)  /* Vista */, "Got 0x%08x\n", hr);
4179     ok(attr == SFGAO_FOLDER || broken(attr == 0) /* Vista */, "Got 0x%08x\n", attr);
4180     attr = 0xdeadbeef;
4181     hr = IShellItemArray_GetAttributes(psia_folders1, SIATTRIBFLAGS_OR, SFGAO_FOLDER, &attr);
4182     ok(hr == S_OK || broken(hr == E_UNEXPECTED)  /* Vista */, "Got 0x%08x\n", hr);
4183     ok(attr == SFGAO_FOLDER || broken(attr == 0) /* Vista */, "Got 0x%08x\n", attr);
4184 
4185     /* [testfolder/testfolder2, testfolder/testfolder3] works */
4186     attr = 0xdeadbeef;
4187     hr = IShellItemArray_GetAttributes(psia_folders2, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attr);
4188     ok(hr == S_OK, "Got 0x%08x\n", hr);
4189     ok(attr == SFGAO_FOLDER, "Got 0x%08x\n", attr);
4190     attr = 0xdeadbeef;
4191     hr = IShellItemArray_GetAttributes(psia_files, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attr);
4192     ok(hr == S_FALSE || broken(hr == S_OK) /* Vista */, "Got 0x%08x\n", hr);
4193     ok(attr == 0, "Got 0x%08x\n", attr);
4194     attr = 0xdeadbeef;
4195     hr = IShellItemArray_GetAttributes(psia_all, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attr);
4196     ok(hr == S_FALSE || broken(hr == S_OK) /* Vista */, "Got 0x%08x\n", hr);
4197     ok(attr == 0, "Got 0x%08x\n", attr);
4198     attr = 0xdeadbeef;
4199     hr = IShellItemArray_GetAttributes(psia_folders2, SIATTRIBFLAGS_OR, SFGAO_FOLDER, &attr);
4200     ok(hr == S_OK, "Got 0x%08x\n", hr);
4201     ok(attr == SFGAO_FOLDER, "Got 0x%08x\n", attr);
4202     attr = 0xdeadbeef;
4203     hr = IShellItemArray_GetAttributes(psia_files, SIATTRIBFLAGS_OR, SFGAO_FOLDER, &attr);
4204     ok(hr == S_FALSE || broken(hr == S_OK) /* Vista */, "Got 0x%08x\n", hr);
4205     ok(attr == 0, "Got 0x%08x\n", attr);
4206     attr = 0xdeadbeef;
4207     hr = IShellItemArray_GetAttributes(psia_all, SIATTRIBFLAGS_OR, SFGAO_FOLDER, &attr);
4208     ok(hr == S_OK, "Got 0x%08x\n", hr);
4209     ok(attr == SFGAO_FOLDER, "Got 0x%08x\n", attr);
4210 
4211     IShellItemArray_Release(psia_folders1);
4212     IShellItemArray_Release(psia_folders2);
4213     IShellItemArray_Release(psia_files);
4214     IShellItemArray_Release(psia_all);
4215 
4216     RemoveDirectoryA(".\\testdir\\testdir3");
4217     Cleanup();
4218 }
4219 
get_empty_cddrive(void)4220 static WCHAR *get_empty_cddrive(void)
4221 {
4222     static WCHAR cdrom_drive[] = {'A',':','\\',0};
4223     DWORD drives = GetLogicalDrives();
4224 
4225     cdrom_drive[0] = 'A';
4226     while (drives)
4227     {
4228         if ((drives & 1) &&
4229             GetDriveTypeW(cdrom_drive) == DRIVE_CDROM &&
4230             GetFileAttributesW(cdrom_drive) == INVALID_FILE_ATTRIBUTES)
4231         {
4232             return cdrom_drive;
4233         }
4234 
4235         drives = drives >> 1;
4236         cdrom_drive[0]++;
4237     }
4238     return NULL;
4239 }
4240 
test_SHParseDisplayName(void)4241 static void test_SHParseDisplayName(void)
4242 {
4243     LPITEMIDLIST pidl1, pidl2;
4244     IShellFolder *desktop;
4245     WCHAR dirW[MAX_PATH];
4246     WCHAR nameW[10];
4247     WCHAR *cdrom;
4248     HRESULT hr;
4249     BOOL ret, is_wow64;
4250 
4251 if (0)
4252 {
4253     /* crashes on native */
4254     SHParseDisplayName(NULL, NULL, NULL, 0, NULL);
4255     nameW[0] = 0;
4256     SHParseDisplayName(nameW, NULL, NULL, 0, NULL);
4257 }
4258 
4259     pidl1 = (LPITEMIDLIST)0xdeadbeef;
4260     hr = SHParseDisplayName(NULL, NULL, &pidl1, 0, NULL);
4261     ok(broken(hr == E_OUTOFMEMORY) /* < Vista */ ||
4262        hr == E_INVALIDARG, "failed %08x\n", hr);
4263     ok(pidl1 == 0, "expected null ptr, got %p\n", pidl1);
4264 
4265     /* dummy name */
4266     nameW[0] = 0;
4267     hr = SHParseDisplayName(nameW, NULL, &pidl1, 0, NULL);
4268     ok(hr == S_OK, "failed %08x\n", hr);
4269     hr = SHGetDesktopFolder(&desktop);
4270     ok(hr == S_OK, "failed %08x\n", hr);
4271     hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, nameW, NULL, &pidl2, NULL);
4272     ok(hr == S_OK, "failed %08x\n", hr);
4273     ret = ILIsEqual(pidl1, pidl2);
4274     ok(ret == TRUE, "expected equal idls\n");
4275     ILFree(pidl1);
4276     ILFree(pidl2);
4277 
4278     /* with path */
4279     GetWindowsDirectoryW( dirW, MAX_PATH );
4280 
4281     hr = SHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
4282     ok(hr == S_OK, "failed %08x\n", hr);
4283     hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, dirW, NULL, &pidl2, NULL);
4284     ok(hr == S_OK, "failed %08x\n", hr);
4285 
4286     ret = ILIsEqual(pidl1, pidl2);
4287     ok(ret == TRUE, "expected equal idls\n");
4288     ILFree(pidl1);
4289     ILFree(pidl2);
4290 
4291     /* system32 is not redirected to syswow64 on WOW64 */
4292     if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
4293     if (is_wow64)
4294     {
4295         UINT len;
4296         *dirW = 0;
4297         len = GetSystemDirectoryW(dirW, MAX_PATH);
4298         ok(len > 0, "GetSystemDirectoryW failed: %u\n", GetLastError());
4299         hr = SHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
4300         ok(hr == S_OK, "failed %08x\n", hr);
4301         *dirW = 0;
4302         len = GetSystemWow64DirectoryW(dirW, MAX_PATH);
4303         ok(len > 0, "GetSystemWow64DirectoryW failed: %u\n", GetLastError());
4304         hr = SHParseDisplayName(dirW, NULL, &pidl2, 0, NULL);
4305         ok(hr == S_OK, "failed %08x\n", hr);
4306         ret = ILIsEqual(pidl1, pidl2);
4307         ok(ret == FALSE, "expected different idls\n");
4308         ILFree(pidl1);
4309         ILFree(pidl2);
4310     }
4311 
4312     IShellFolder_Release(desktop);
4313 
4314     cdrom = get_empty_cddrive();
4315     if (!cdrom)
4316         skip("No empty cdrom drive found, skipping test\n");
4317     else
4318     {
4319         hr = SHParseDisplayName(cdrom, NULL, &pidl1, 0, NULL);
4320         ok(hr == S_OK, "failed %08x\n", hr);
4321         if (SUCCEEDED(hr)) ILFree(pidl1);
4322     }
4323 }
4324 
test_desktop_IPersist(void)4325 static void test_desktop_IPersist(void)
4326 {
4327     IShellFolder *desktop;
4328     IPersist *persist;
4329     IPersistFolder2 *ppf2;
4330     CLSID clsid;
4331     HRESULT hr;
4332 
4333     hr = SHGetDesktopFolder(&desktop);
4334     ok(hr == S_OK, "failed %08x\n", hr);
4335 
4336     hr = IShellFolder_QueryInterface(desktop, &IID_IPersist, (void**)&persist);
4337     ok(hr == S_OK, "failed %08x\n", hr);
4338 
4339     if (hr == S_OK)
4340     {
4341     if (0)
4342     {
4343         /* crashes on native */
4344         IPersist_GetClassID(persist, NULL);
4345     }
4346         memset(&clsid, 0, sizeof(clsid));
4347         hr = IPersist_GetClassID(persist, &clsid);
4348         ok(hr == S_OK, "failed %08x\n", hr);
4349         ok(IsEqualIID(&CLSID_ShellDesktop, &clsid), "Expected CLSID_ShellDesktop\n");
4350         IPersist_Release(persist);
4351     }
4352 
4353     hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder2, (void**)&ppf2);
4354     ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* pre-Vista */, "failed %08x\n", hr);
4355     if(SUCCEEDED(hr))
4356     {
4357         IPersistFolder *ppf;
4358         LPITEMIDLIST pidl;
4359         hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder, (void**)&ppf);
4360         ok(hr == S_OK, "IID_IPersistFolder2 without IID_IPersistFolder.\n");
4361         if(SUCCEEDED(hr))
4362             IPersistFolder_Release(ppf);
4363 
4364         todo_wine {
4365             hr = IPersistFolder2_Initialize(ppf2, NULL);
4366             ok(hr == S_OK, "got %08x\n", hr);
4367         }
4368 
4369         pidl = NULL;
4370         hr = IPersistFolder2_GetCurFolder(ppf2, &pidl);
4371         ok(hr == S_OK, "got %08x\n", hr);
4372         ok(pidl != NULL, "pidl was NULL.\n");
4373         if(SUCCEEDED(hr)) ILFree(pidl);
4374 
4375         IPersistFolder2_Release(ppf2);
4376     }
4377 
4378     IShellFolder_Release(desktop);
4379 }
4380 
test_contextmenu_qi(IContextMenu * menu,BOOL todo)4381 static void test_contextmenu_qi(IContextMenu *menu, BOOL todo)
4382 {
4383     IUnknown *unk;
4384     HRESULT hr;
4385 
4386     hr = IContextMenu_QueryInterface(menu, &IID_IShellExtInit, (void **)&unk);
4387 todo_wine_if(todo)
4388     ok(hr == S_OK, "Failed to get IShellExtInit, hr %#x.\n", hr);
4389 if (hr == S_OK)
4390     IUnknown_Release(unk);
4391 
4392     hr = IContextMenu_QueryInterface(menu, &IID_IObjectWithSite, (void **)&unk);
4393 todo_wine_if(todo)
4394     ok(hr == S_OK, "Failed to get IShellExtInit, hr %#x.\n", hr);
4395 if (hr == S_OK)
4396     IUnknown_Release(unk);
4397 }
4398 
test_contextmenu(IContextMenu * menu,BOOL background)4399 static void test_contextmenu(IContextMenu *menu, BOOL background)
4400 {
4401     HMENU hmenu = CreatePopupMenu();
4402     const int id_upper_limit = 32767;
4403     const int baseItem = 0x40;
4404     INT max_id, max_id_check;
4405     UINT count, i;
4406     HRESULT hr;
4407 
4408     test_contextmenu_qi(menu, FALSE);
4409 
4410     hr = IContextMenu_QueryContextMenu(menu, hmenu, 0, baseItem, id_upper_limit, CMF_NORMAL);
4411     ok(SUCCEEDED(hr), "Failed to query the menu, hr %#x.\n", hr);
4412 
4413     max_id = HRESULT_CODE(hr) - 1; /* returns max_id + 1 */
4414     ok(max_id <= id_upper_limit, "Got %d\n", max_id);
4415     count = GetMenuItemCount(hmenu);
4416     ok(count, "Got %d\n", count);
4417 
4418     max_id_check = 0;
4419     for (i = 0; i < count; i++)
4420     {
4421         MENUITEMINFOA mii;
4422         INT res;
4423         char buf[255], buf2[255];
4424         ZeroMemory(&mii, sizeof(MENUITEMINFOA));
4425         mii.cbSize = sizeof(MENUITEMINFOA);
4426         mii.fMask = MIIM_ID | MIIM_FTYPE | MIIM_STRING;
4427         mii.dwTypeData = buf2;
4428         mii.cch = sizeof(buf2);
4429 
4430         res = GetMenuItemInfoA(hmenu, i, TRUE, &mii);
4431         ok(res, "Failed to get menu item info, error %d.\n", GetLastError());
4432 
4433         ok((mii.wID <= id_upper_limit) || (mii.fType & MFT_SEPARATOR),
4434             "Got non-separator ID out of range: %d (type: %x)\n", mii.wID, mii.fType);
4435         if (!(mii.fType & MFT_SEPARATOR))
4436         {
4437             max_id_check = (mii.wID > max_id_check) ? mii.wID : max_id_check;
4438             hr = IContextMenu_GetCommandString(menu, mii.wID - baseItem, GCS_VERBA, 0, buf, sizeof(buf));
4439         todo_wine_if(background)
4440             ok(SUCCEEDED(hr) || hr == E_NOTIMPL, "for id 0x%x got 0x%08x (menustr: %s)\n", mii.wID - baseItem, hr, mii.dwTypeData);
4441             if (SUCCEEDED(hr))
4442                 trace("for id 0x%x got string %s (menu string: %s)\n", mii.wID - baseItem, buf, mii.dwTypeData);
4443             else if (hr == E_NOTIMPL)
4444                 trace("for id 0x%x got E_NOTIMPL (menu string: %s)\n", mii.wID - baseItem, mii.dwTypeData);
4445         }
4446     }
4447     max_id_check -= baseItem;
4448     ok((max_id_check == max_id) ||
4449        (max_id_check == max_id-1) || /* Win 7 */
4450        (max_id_check == max_id-2) || /* Win 8 */
4451        (max_id_check == max_id-3),
4452        "Not equal (or near equal), got %d and %d\n", max_id_check, max_id);
4453 
4454     if (count)
4455     {
4456         CMINVOKECOMMANDINFO cmi;
4457 
4458         memset(&cmi, 0, sizeof(CMINVOKECOMMANDINFO));
4459         cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
4460 
4461         /* Attempt to execute a nonexistent command */
4462         cmi.lpVerb = MAKEINTRESOURCEA(9999);
4463         hr = IContextMenu_InvokeCommand(menu, &cmi);
4464     todo_wine_if(background)
4465         ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
4466 
4467         cmi.lpVerb = "foobar_wine_test";
4468         hr = IContextMenu_InvokeCommand(menu, &cmi);
4469     todo_wine_if(background)
4470         ok((hr == E_INVALIDARG) || (hr == E_FAIL /* Win7 */) ||
4471            (hr == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION) /* Vista */),
4472             "Unexpected hr %#x.\n", hr);
4473     }
4474 
4475     DestroyMenu(hmenu);
4476 }
4477 
test_GetUIObject(void)4478 static void test_GetUIObject(void)
4479 {
4480     IShellFolder *psf_desktop;
4481     IContextMenu *pcm;
4482     LPITEMIDLIST pidl;
4483     HRESULT hr;
4484     WCHAR path[MAX_PATH];
4485     const WCHAR filename[] =
4486         {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
4487     LPCITEMIDLIST pidl_child;
4488     IShellFolder *psf;
4489 
4490     GetCurrentDirectoryW(MAX_PATH, path);
4491     if (!path[0])
4492     {
4493         skip("GetCurrentDirectoryW returned an empty string.\n");
4494         return;
4495     }
4496     lstrcatW(path, filename);
4497     SHGetDesktopFolder(&psf_desktop);
4498 
4499     CreateFilesFolders();
4500 
4501     hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, path, NULL, &pidl, 0);
4502     ok(hr == S_OK, "Got 0x%08x\n", hr);
4503 
4504     hr = SHBindToParent(pidl, &IID_IShellFolder, (void **)&psf, &pidl_child);
4505     ok(hr == S_OK, "Failed to bind to folder, hr %#x.\n", hr);
4506 
4507     /* Item menu */
4508     hr = IShellFolder_GetUIObjectOf(psf, NULL, 1, &pidl_child, &IID_IContextMenu, NULL, (void **)&pcm);
4509     ok(hr == S_OK, "GetUIObjectOf() failed, hr %#x.\n", hr);
4510     test_contextmenu(pcm, FALSE);
4511     IContextMenu_Release(pcm);
4512 
4513     /* Background menu */
4514     hr = IShellFolder_GetUIObjectOf(psf_desktop, NULL, 0, NULL, &IID_IContextMenu, NULL, (void **)&pcm);
4515     ok(hr == S_OK, "GetUIObjectOf() failed, hr %#x.\n", hr);
4516     test_contextmenu(pcm, TRUE);
4517     IContextMenu_Release(pcm);
4518 
4519     IShellFolder_Release(psf);
4520     ILFree(pidl);
4521 
4522     IShellFolder_Release(psf_desktop);
4523     Cleanup();
4524 }
4525 
4526 #define verify_pidl(i,p) r_verify_pidl(__LINE__, i, p)
r_verify_pidl(unsigned l,LPCITEMIDLIST pidl,const WCHAR * path)4527 static void r_verify_pidl(unsigned l, LPCITEMIDLIST pidl, const WCHAR *path)
4528 {
4529     LPCITEMIDLIST child;
4530     IShellFolder *parent;
4531     STRRET filename;
4532     HRESULT hr;
4533 
4534     if(path){
4535         if(!pidl){
4536             ok_(__FILE__,l)(0, "didn't get expected path (%s), instead: NULL\n", wine_dbgstr_w(path));
4537             return;
4538         }
4539 
4540         hr = SHBindToParent(pidl, &IID_IShellFolder, (void **)&parent, &child);
4541         ok_(__FILE__,l)(hr == S_OK, "SHBindToParent failed: 0x%08x\n", hr);
4542         if(FAILED(hr))
4543             return;
4544 
4545         hr = IShellFolder_GetDisplayNameOf(parent, child, SHGDN_FORPARSING, &filename);
4546         ok_(__FILE__,l)(hr == S_OK, "GetDisplayNameOf failed: 0x%08x\n", hr);
4547         if(FAILED(hr)){
4548             IShellFolder_Release(parent);
4549             return;
4550         }
4551 
4552         ok_(__FILE__,l)(filename.uType == STRRET_WSTR || filename.uType == STRRET_CSTR,
4553                 "Got unexpected string type: %d\n", filename.uType);
4554         if(filename.uType == STRRET_WSTR){
4555             ok_(__FILE__,l)(lstrcmpW(path, U(filename).pOleStr) == 0,
4556                     "didn't get expected path (%s), instead: %s\n",
4557                      wine_dbgstr_w(path), wine_dbgstr_w(U(filename).pOleStr));
4558             SHFree(U(filename).pOleStr);
4559         }else if(filename.uType == STRRET_CSTR){
4560             ok_(__FILE__,l)(strcmp_wa(path, U(filename).cStr) == 0,
4561                     "didn't get expected path (%s), instead: %s\n",
4562                      wine_dbgstr_w(path), U(filename).cStr);
4563         }
4564 
4565         IShellFolder_Release(parent);
4566     }else
4567         ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
4568 }
4569 
test_SHSimpleIDListFromPath(void)4570 static void test_SHSimpleIDListFromPath(void)
4571 {
4572     const WCHAR adirW[] = {'C',':','\\','s','i','d','l','f','p','d','i','r',0};
4573     const CHAR adirA[] = "C:\\sidlfpdir";
4574     BOOL br, is_unicode = !(GetVersion() & 0x80000000);
4575 
4576     LPITEMIDLIST pidl = NULL;
4577 
4578     br = CreateDirectoryA(adirA, NULL);
4579     ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
4580 
4581     if(is_unicode)
4582         pidl = SHSimpleIDListFromPath(adirW);
4583     else
4584         pidl = SHSimpleIDListFromPath((const WCHAR *)adirA);
4585     verify_pidl(pidl, adirW);
4586     ILFree(pidl);
4587 
4588     br = RemoveDirectoryA(adirA);
4589     ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4590 
4591     if(is_unicode)
4592         pidl = SHSimpleIDListFromPath(adirW);
4593     else
4594         pidl = SHSimpleIDListFromPath((const WCHAR *)adirA);
4595     verify_pidl(pidl, adirW);
4596     ILFree(pidl);
4597 }
4598 
4599 /* IFileSystemBindData impl */
fsbd_QueryInterface(IFileSystemBindData * fsbd,REFIID riid,void ** ppv)4600 static HRESULT WINAPI fsbd_QueryInterface(IFileSystemBindData *fsbd,
4601         REFIID riid, void **ppv)
4602 {
4603     if(IsEqualIID(riid, &IID_IFileSystemBindData) ||
4604             IsEqualIID(riid, &IID_IUnknown)){
4605         *ppv = fsbd;
4606         return S_OK;
4607     }
4608     return E_NOINTERFACE;
4609 }
4610 
fsbd_AddRef(IFileSystemBindData * fsbd)4611 static ULONG WINAPI fsbd_AddRef(IFileSystemBindData *fsbd)
4612 {
4613     return 2;
4614 }
4615 
fsbd_Release(IFileSystemBindData * fsbd)4616 static ULONG WINAPI fsbd_Release(IFileSystemBindData *fsbd)
4617 {
4618     return 1;
4619 }
4620 
fsbd_SetFindData(IFileSystemBindData * fsbd,const WIN32_FIND_DATAW * pfd)4621 static HRESULT WINAPI fsbd_SetFindData(IFileSystemBindData *fsbd,
4622         const WIN32_FIND_DATAW *pfd)
4623 {
4624     ok(0, "SetFindData called\n");
4625     return E_NOTIMPL;
4626 }
4627 
fsbd_GetFindData_nul(IFileSystemBindData * fsbd,WIN32_FIND_DATAW * pfd)4628 static HRESULT WINAPI fsbd_GetFindData_nul(IFileSystemBindData *fsbd,
4629         WIN32_FIND_DATAW *pfd)
4630 {
4631     memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
4632     return S_OK;
4633 }
4634 
fsbd_GetFindData_junk(IFileSystemBindData * fsbd,WIN32_FIND_DATAW * pfd)4635 static HRESULT WINAPI fsbd_GetFindData_junk(IFileSystemBindData *fsbd,
4636         WIN32_FIND_DATAW *pfd)
4637 {
4638     memset(pfd, 0xef, sizeof(WIN32_FIND_DATAW));
4639     return S_OK;
4640 }
4641 
fsbd_GetFindData_invalid(IFileSystemBindData * fsbd,WIN32_FIND_DATAW * pfd)4642 static HRESULT WINAPI fsbd_GetFindData_invalid(IFileSystemBindData *fsbd,
4643         WIN32_FIND_DATAW *pfd)
4644 {
4645     memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
4646     *pfd->cFileName = 'a';
4647     *pfd->cAlternateFileName = 'a';
4648     return S_OK;
4649 }
4650 
fsbd_GetFindData_valid(IFileSystemBindData * fsbd,WIN32_FIND_DATAW * pfd)4651 static HRESULT WINAPI fsbd_GetFindData_valid(IFileSystemBindData *fsbd,
4652         WIN32_FIND_DATAW *pfd)
4653 {
4654     static const WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4655     HANDLE handle = FindFirstFileW(adirW, pfd);
4656     FindClose(handle);
4657     return S_OK;
4658 }
4659 
fsbd_GetFindData_fail(IFileSystemBindData * fsbd,WIN32_FIND_DATAW * pfd)4660 static HRESULT WINAPI fsbd_GetFindData_fail(IFileSystemBindData *fsbd,
4661         WIN32_FIND_DATAW *pfd)
4662 {
4663     return E_FAIL;
4664 }
4665 
4666 static IFileSystemBindDataVtbl fsbdVtbl = {
4667     fsbd_QueryInterface,
4668     fsbd_AddRef,
4669     fsbd_Release,
4670     fsbd_SetFindData,
4671     NULL
4672 };
4673 
4674 static IFileSystemBindData fsbd = { &fsbdVtbl };
4675 
test_ParseDisplayNamePBC(void)4676 static void test_ParseDisplayNamePBC(void)
4677 {
4678     WCHAR wFileSystemBindData[] =
4679         {'F','i','l','e',' ','S','y','s','t','e','m',' ','B','i','n','d',' ','D','a','t','a',0};
4680     WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4681     WCHAR afileW[] = {'C',':','\\','f','s','b','d','d','i','r','\\','f','i','l','e','.','t','x','t',0};
4682     WCHAR afile2W[] = {'C',':','\\','f','s','b','d','d','i','r','\\','s','\\','f','i','l','e','.','t','x','t',0};
4683     const HRESULT exp_err = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
4684 
4685     IShellFolder *psf;
4686     IBindCtx *pbc;
4687     HRESULT hres;
4688     ITEMIDLIST *pidl;
4689 
4690     /* Check if we support WCHAR functions */
4691     SetLastError(0xdeadbeef);
4692     lstrcmpiW(adirW, adirW);
4693     if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED){
4694         win_skip("Most W-calls are not implemented\n");
4695         return;
4696     }
4697 
4698     hres = SHGetDesktopFolder(&psf);
4699     ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
4700     if(FAILED(hres)){
4701         win_skip("Failed to get IShellFolder, can't run tests\n");
4702         return;
4703     }
4704 
4705     /* fails on unknown dir with no IBindCtx */
4706     hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, adirW, NULL, &pidl, NULL);
4707     ok(hres == exp_err, "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4708     hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, afileW, NULL, &pidl, NULL);
4709     ok(hres == exp_err, "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4710     hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, afile2W, NULL, &pidl, NULL);
4711     ok(hres == exp_err, "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4712 
4713     /* fails on unknown dir with IBindCtx with no IFileSystemBindData */
4714     hres = CreateBindCtx(0, &pbc);
4715     ok(hres == S_OK, "CreateBindCtx failed: 0x%08x\n", hres);
4716 
4717     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4718     ok(hres == exp_err, "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4719     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4720     ok(hres == exp_err, "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4721     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4722     ok(hres == exp_err, "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4723 
4724     /* unknown dir with IBindCtx with IFileSystemBindData */
4725     hres = IBindCtx_RegisterObjectParam(pbc, wFileSystemBindData, (IUnknown*)&fsbd);
4726     ok(hres == S_OK, "RegisterObjectParam failed: 0x%08x\n", hres);
4727 
4728     /* return E_FAIL from GetFindData */
4729     pidl = (ITEMIDLIST*)0xdeadbeef;
4730     fsbdVtbl.GetFindData = fsbd_GetFindData_fail;
4731     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4732     ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4733     if(SUCCEEDED(hres)){
4734         verify_pidl(pidl, adirW);
4735         ILFree(pidl);
4736     }
4737 
4738     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4739     ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4740     if(SUCCEEDED(hres)){
4741         verify_pidl(pidl, afileW);
4742         ILFree(pidl);
4743     }
4744 
4745     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4746     ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4747     if(SUCCEEDED(hres)){
4748         verify_pidl(pidl, afile2W);
4749         ILFree(pidl);
4750     }
4751 
4752     /* set FIND_DATA struct to NULLs */
4753     pidl = (ITEMIDLIST*)0xdeadbeef;
4754     fsbdVtbl.GetFindData = fsbd_GetFindData_nul;
4755     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4756     ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4757     if(SUCCEEDED(hres)){
4758         verify_pidl(pidl, adirW);
4759         ILFree(pidl);
4760     }
4761 
4762     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4763     ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4764     if(SUCCEEDED(hres)){
4765         verify_pidl(pidl, afileW);
4766         ILFree(pidl);
4767     }
4768 
4769     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4770     ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4771     if(SUCCEEDED(hres)){
4772         verify_pidl(pidl, afile2W);
4773         ILFree(pidl);
4774     }
4775 
4776     /* set FIND_DATA struct to junk */
4777     pidl = (ITEMIDLIST*)0xdeadbeef;
4778     fsbdVtbl.GetFindData = fsbd_GetFindData_junk;
4779     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4780     ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4781     if(SUCCEEDED(hres)){
4782         verify_pidl(pidl, adirW);
4783         ILFree(pidl);
4784     }
4785 
4786     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4787     ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4788     if(SUCCEEDED(hres)){
4789         verify_pidl(pidl, afileW);
4790         ILFree(pidl);
4791     }
4792 
4793     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4794     ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4795     if(SUCCEEDED(hres)){
4796         verify_pidl(pidl, afile2W);
4797         ILFree(pidl);
4798     }
4799 
4800     /* set FIND_DATA struct to invalid data */
4801     pidl = (ITEMIDLIST*)0xdeadbeef;
4802     fsbdVtbl.GetFindData = fsbd_GetFindData_invalid;
4803     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4804     ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4805     if(SUCCEEDED(hres)){
4806         verify_pidl(pidl, adirW);
4807         ILFree(pidl);
4808     }
4809 
4810     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4811     ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4812     if(SUCCEEDED(hres)){
4813         verify_pidl(pidl, afileW);
4814         ILFree(pidl);
4815     }
4816 
4817     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4818     ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4819     if(SUCCEEDED(hres)){
4820         verify_pidl(pidl, afile2W);
4821         ILFree(pidl);
4822     }
4823 
4824     /* set FIND_DATA struct to valid data */
4825     pidl = (ITEMIDLIST*)0xdeadbeef;
4826     fsbdVtbl.GetFindData = fsbd_GetFindData_valid;
4827     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4828     ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4829     if(SUCCEEDED(hres)){
4830         verify_pidl(pidl, adirW);
4831         ILFree(pidl);
4832     }
4833 
4834     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4835     ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4836     if(SUCCEEDED(hres)){
4837         verify_pidl(pidl, afileW);
4838         ILFree(pidl);
4839     }
4840 
4841     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4842     ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4843     if(SUCCEEDED(hres)){
4844         verify_pidl(pidl, afile2W);
4845         ILFree(pidl);
4846     }
4847 
4848     IBindCtx_Release(pbc);
4849     IShellFolder_Release(psf);
4850 }
4851 
4852 static const CHAR testwindow_class[] = "testwindow";
4853 #define WM_USER_NOTIFY (WM_APP+1)
4854 
4855 struct ChNotifyTest {
4856     const char id[256];
4857     const UINT notify_count;
4858     UINT missing_events;
4859     UINT signal;
4860     const char path_1[256];
4861     const char path_2[256];
4862 } chnotify_tests[] = {
4863     {"MKDIR", 1, 0, SHCNE_MKDIR, "C:\\shell32_cn_test\\test", ""},
4864     {"CREATE", 1, 0, SHCNE_CREATE, "C:\\shell32_cn_test\\test\\file.txt", ""},
4865     {"RMDIR", 1, 0, SHCNE_RMDIR, "C:\\shell32_cn_test\\test", ""},
4866 };
4867 
4868 struct ChNotifyTest *exp_data;
4869 BOOL test_new_delivery_flag;
4870 
testwindow_wndproc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)4871 static LRESULT CALLBACK testwindow_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
4872 {
4873     LONG signal = (LONG)lparam;
4874 
4875     switch(msg){
4876     case WM_USER_NOTIFY:
4877         if(exp_data->missing_events > 0) {
4878             WCHAR *path1, *path2;
4879             LPITEMIDLIST *pidls = (LPITEMIDLIST*)wparam;
4880             HANDLE hLock = NULL;
4881 
4882             if(test_new_delivery_flag) {
4883                 hLock = SHChangeNotification_Lock((HANDLE)wparam, lparam, &pidls, &signal);
4884                 ok(hLock != NULL, "SHChangeNotification_Lock returned NULL\n");
4885             }
4886 
4887             ok(exp_data->signal == signal,
4888                     "%s: expected notification type %x, got: %x\n",
4889                     exp_data->id, exp_data->signal, signal);
4890 
4891             trace("verifying pidls for: %s\n", exp_data->id);
4892             path1 = make_wstr(exp_data->path_1);
4893             path2 = make_wstr(exp_data->path_2);
4894             verify_pidl(pidls[0], path1);
4895             verify_pidl(pidls[1], path2);
4896             heap_free(path1);
4897             heap_free(path2);
4898 
4899             exp_data->missing_events--;
4900 
4901             if(test_new_delivery_flag)
4902                 SHChangeNotification_Unlock(hLock);
4903         }else
4904             ok(0, "Didn't expect a WM_USER_NOTIFY message (event: %x)\n", signal);
4905         return 0;
4906     }
4907     return DefWindowProcA(hwnd, msg, wparam, lparam);
4908 }
4909 
register_testwindow_class(void)4910 static void register_testwindow_class(void)
4911 {
4912     WNDCLASSEXA cls;
4913     ATOM ret;
4914 
4915     ZeroMemory(&cls, sizeof(cls));
4916     cls.cbSize = sizeof(cls);
4917     cls.style = 0;
4918     cls.lpfnWndProc = testwindow_wndproc;
4919     cls.hInstance = GetModuleHandleA(NULL);
4920     cls.lpszClassName = testwindow_class;
4921 
4922     SetLastError(0);
4923     ret = RegisterClassExA(&cls);
4924     ok(ret != 0, "RegisterClassExA failed: %d\n", GetLastError());
4925 }
4926 
4927 /* SHCNF_FLUSH doesn't seem to work as advertised for SHCNF_PATHA, so we
4928  * have to poll repeatedly for the message to appear */
do_events(void)4929 static void do_events(void)
4930 {
4931     int c = 0;
4932     while (exp_data->missing_events && (c++ < 10)){
4933         MSG msg;
4934         while(PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)){
4935             TranslateMessage(&msg);
4936             DispatchMessageA(&msg);
4937         }
4938         if(exp_data->missing_events)
4939             Sleep(500);
4940     }
4941     trace("%s: took %d tries\n", exp_data->id, c);
4942 }
4943 
test_SHChangeNotify(BOOL test_new_delivery)4944 static void test_SHChangeNotify(BOOL test_new_delivery)
4945 {
4946     HWND wnd;
4947     ULONG notifyID, i;
4948     HRESULT hr;
4949     BOOL br, has_unicode;
4950     SHChangeNotifyEntry entries[1];
4951     const CHAR root_dirA[] = "C:\\shell32_cn_test";
4952     const WCHAR root_dirW[] = {'C',':','\\','s','h','e','l','l','3','2','_','c','n','_','t','e','s','t',0};
4953 
4954     trace("SHChangeNotify tests (%x)\n", test_new_delivery);
4955 
4956     CreateDirectoryW(NULL, NULL);
4957     has_unicode = !(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED);
4958 
4959     test_new_delivery_flag = test_new_delivery;
4960     if(!test_new_delivery)
4961         register_testwindow_class();
4962 
4963     wnd = CreateWindowExA(0, testwindow_class, testwindow_class, 0,
4964             CW_USEDEFAULT, CW_USEDEFAULT, 130, 105,
4965             NULL, NULL, GetModuleHandleA(NULL), 0);
4966     ok(wnd != NULL, "Failed to make a window\n");
4967 
4968     br = CreateDirectoryA(root_dirA, NULL);
4969     ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
4970 
4971     entries[0].pidl = NULL;
4972     if(has_unicode)
4973         hr = SHILCreateFromPath(root_dirW, (LPITEMIDLIST*)&entries[0].pidl, 0);
4974     else
4975         hr = SHILCreateFromPath((const void *)root_dirA, (LPITEMIDLIST*)&entries[0].pidl, 0);
4976     ok(hr == S_OK, "SHILCreateFromPath failed: 0x%08x\n", hr);
4977     entries[0].fRecursive = TRUE;
4978 
4979     notifyID = SHChangeNotifyRegister(wnd, !test_new_delivery ? SHCNRF_ShellLevel : SHCNRF_ShellLevel|SHCNRF_NewDelivery,
4980             SHCNE_ALLEVENTS, WM_USER_NOTIFY, 1, entries);
4981     ok(notifyID != 0, "Failed to register a window for change notifications\n");
4982 
4983     for (i = 0; i < ARRAY_SIZE(chnotify_tests); ++i)
4984     {
4985         exp_data = chnotify_tests + i;
4986 
4987         exp_data->missing_events = exp_data->notify_count;
4988         SHChangeNotify(exp_data->signal, SHCNF_PATHA | SHCNF_FLUSH,
4989                 exp_data->path_1[0] ? exp_data->path_1 : NULL,
4990                 exp_data->path_2[0] ? exp_data->path_2 : NULL);
4991         do_events();
4992         ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
4993 
4994         if(has_unicode){
4995             WCHAR *path1, *path2;
4996 
4997             path1 = make_wstr(exp_data->path_1);
4998             path2 = make_wstr(exp_data->path_2);
4999 
5000             exp_data->missing_events = exp_data->notify_count;
5001             SHChangeNotify(exp_data->signal, SHCNF_PATHW | SHCNF_FLUSH, path1, path2);
5002             do_events();
5003             ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
5004 
5005             heap_free(path1);
5006             heap_free(path2);
5007         }
5008     }
5009 
5010     SHChangeNotifyDeregister(notifyID);
5011     DestroyWindow(wnd);
5012 
5013     ILFree((LPITEMIDLIST)entries[0].pidl);
5014     br = RemoveDirectoryA(root_dirA);
5015     ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
5016 }
5017 
test_SHCreateDefaultContextMenu(void)5018 static void test_SHCreateDefaultContextMenu(void)
5019 {
5020     HKEY keys[16];
5021     WCHAR path[MAX_PATH];
5022     IShellFolder *desktop,*folder;
5023     IPersistFolder2 *persist;
5024     IContextMenu *cmenu;
5025     LONG status;
5026     LPITEMIDLIST pidlFolder, pidl_child, pidl;
5027     DEFCONTEXTMENU cminfo;
5028     HRESULT hr;
5029     UINT i;
5030     const WCHAR filename[] =
5031         {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
5032     if(!pSHCreateDefaultContextMenu)
5033     {
5034         win_skip("SHCreateDefaultContextMenu missing.\n");
5035         return;
5036     }
5037 
5038     GetCurrentDirectoryW(MAX_PATH, path);
5039     if (!path[0])
5040     {
5041         skip("GetCurrentDirectoryW returned an empty string.\n");
5042         return;
5043     }
5044     lstrcatW(path, filename);
5045     SHGetDesktopFolder(&desktop);
5046 
5047     CreateFilesFolders();
5048 
5049     hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, path, NULL, &pidl, 0);
5050     ok(hr == S_OK, "Got 0x%08x\n", hr);
5051     if(SUCCEEDED(hr))
5052     {
5053         hr = SHBindToParent(pidl, &IID_IShellFolder, (void **)&folder, (const ITEMIDLIST **)&pidl_child);
5054         ok(hr == S_OK, "Got 0x%08x\n", hr);
5055 
5056         IShellFolder_QueryInterface(folder,&IID_IPersistFolder2,(void**)&persist);
5057         IPersistFolder2_GetCurFolder(persist,&pidlFolder);
5058         IPersistFolder2_Release(persist);
5059         if(SUCCEEDED(hr))
5060         {
5061             cminfo.hwnd=NULL;
5062             cminfo.pcmcb=NULL;
5063             cminfo.psf=folder;
5064             cminfo.pidlFolder=NULL;
5065             cminfo.apidl=(LPCITEMIDLIST*)&pidl_child;
5066             cminfo.cidl=1;
5067             cminfo.aKeys=NULL;
5068             cminfo.cKeys=0;
5069             cminfo.punkAssociationInfo=NULL;
5070 
5071             hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
5072             ok(hr==S_OK,"Got 0x%08x\n", hr);
5073             test_contextmenu_qi(cmenu, TRUE);
5074             IContextMenu_Release(cmenu);
5075 
5076             cminfo.pidlFolder=pidlFolder;
5077             hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
5078             ok(hr==S_OK,"Got 0x%08x\n", hr);
5079             test_contextmenu_qi(cmenu, TRUE);
5080             IContextMenu_Release(cmenu);
5081 
5082             status = RegOpenKeyExA(HKEY_CLASSES_ROOT,"*",0,KEY_READ,keys);
5083             if(status==ERROR_SUCCESS){
5084                 for(i=1;i<16;i++)
5085                     keys[i]=keys[0];
5086                 cminfo.aKeys=keys;
5087                 cminfo.cKeys=16;
5088                 hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
5089                 RegCloseKey(keys[0]);
5090                 ok(hr==S_OK,"Got 0x%08x\n", hr);
5091                 IContextMenu_Release(cmenu);
5092             }
5093         }
5094         ILFree(pidlFolder);
5095         IShellFolder_Release(folder);
5096     }
5097     IShellFolder_Release(desktop);
5098     ILFree(pidl);
5099     Cleanup();
5100 }
5101 
test_DataObject(void)5102 static void test_DataObject(void)
5103 {
5104     IShellFolder *desktop;
5105     IDataObject *data_obj;
5106     HRESULT hres;
5107     IEnumIDList *peidl;
5108     LPITEMIDLIST apidl;
5109     FORMATETC fmt;
5110     DWORD cf_shellidlist;
5111     STGMEDIUM medium;
5112 
5113     SHGetDesktopFolder(&desktop);
5114 
5115     hres = IShellFolder_EnumObjects(desktop, NULL,
5116             SHCONTF_NONFOLDERS|SHCONTF_FOLDERS|SHCONTF_INCLUDEHIDDEN, &peidl);
5117     ok(hres == S_OK, "got %x\n", hres);
5118 
5119     if(IEnumIDList_Next(peidl, 1, &apidl, NULL) != S_OK) {
5120         skip("no files on desktop - skipping GetDataObject tests\n");
5121         IEnumIDList_Release(peidl);
5122         IShellFolder_Release(desktop);
5123         return;
5124     }
5125     IEnumIDList_Release(peidl);
5126 
5127     hres = IShellFolder_GetUIObjectOf(desktop, NULL, 1, (LPCITEMIDLIST*)&apidl,
5128             &IID_IDataObject, NULL, (void**)&data_obj);
5129     ok(hres == S_OK, "got %x\n", hres);
5130     ILFree(apidl);
5131     IShellFolder_Release(desktop);
5132 
5133     cf_shellidlist = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW);
5134     fmt.cfFormat = cf_shellidlist;
5135     fmt.ptd = NULL;
5136     fmt.dwAspect = DVASPECT_CONTENT;
5137     fmt.lindex = -1;
5138     fmt.tymed = TYMED_HGLOBAL;
5139     hres = IDataObject_QueryGetData(data_obj, &fmt);
5140     ok(hres == S_OK, "got %x\n", hres);
5141 
5142     fmt.tymed = TYMED_HGLOBAL | TYMED_ISTREAM;
5143     hres = IDataObject_QueryGetData(data_obj, &fmt);
5144     ok(hres == S_OK, "got %x\n", hres);
5145 
5146     fmt.tymed = TYMED_ISTREAM;
5147     hres = IDataObject_QueryGetData(data_obj, &fmt);
5148     todo_wine ok(hres == S_FALSE, "got %x\n", hres);
5149 
5150     fmt.tymed = TYMED_HGLOBAL | TYMED_ISTREAM;
5151     hres = IDataObject_GetData(data_obj, &fmt, &medium);
5152     ok(hres == S_OK, "got %x\n", hres);
5153     ok(medium.tymed == TYMED_HGLOBAL, "medium.tymed = %x\n", medium.tymed);
5154     ReleaseStgMedium(&medium);
5155 
5156     IDataObject_Release(data_obj);
5157 }
5158 
test_GetDefaultColumn(void)5159 static void test_GetDefaultColumn(void)
5160 {
5161     static const CLSID *folders[] =
5162     {
5163         &CLSID_MyComputer,
5164         &CLSID_MyDocuments,
5165         &CLSID_ControlPanel,
5166         &CLSID_NetworkPlaces,
5167         &CLSID_Printers,
5168         &CLSID_RecycleBin,
5169         &CLSID_ShellDesktop,
5170     };
5171     HRESULT hr;
5172     int i;
5173 
5174     CoInitialize(NULL);
5175 
5176     for (i = 0; i < ARRAY_SIZE(folders); i++)
5177     {
5178         IShellFolder2 *folder;
5179         ULONG sort, display;
5180 
5181         hr = CoCreateInstance(folders[i], NULL, CLSCTX_INPROC_SERVER, &IID_IShellFolder2, (void **)&folder);
5182         if (hr != S_OK)
5183         {
5184             win_skip("Failed to create folder %s, hr %#x.\n", wine_dbgstr_guid(folders[i]), hr);
5185             continue;
5186         }
5187 
5188         hr = IShellFolder2_GetDefaultColumn(folder, 0, NULL, NULL);
5189         ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
5190 
5191         sort = display = 123;
5192         hr = IShellFolder2_GetDefaultColumn(folder, 0, &sort, &display);
5193         ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
5194         ok(sort == 123 && display == 123, "Unexpected default column.\n");
5195 
5196         display = 123;
5197         hr = IShellFolder2_GetDefaultColumn(folder, 0, NULL, &display);
5198         ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
5199         ok(display == 123, "Unexpected default column.\n");
5200 
5201         sort = 123;
5202         hr = IShellFolder2_GetDefaultColumn(folder, 0, &sort, NULL);
5203         ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
5204         ok(sort == 123, "Unexpected default column.\n");
5205 
5206         IShellFolder2_Release(folder);
5207     }
5208 
5209     CoUninitialize();
5210 }
5211 
test_GetDefaultSearchGUID(void)5212 static void test_GetDefaultSearchGUID(void)
5213 {
5214     static const CLSID *folders[] =
5215     {
5216         &CLSID_MyComputer,
5217         &CLSID_MyDocuments,
5218         &CLSID_ControlPanel,
5219         &CLSID_NetworkPlaces,
5220         &CLSID_Printers,
5221         &CLSID_RecycleBin,
5222         &CLSID_ShellDesktop,
5223     };
5224     HRESULT hr;
5225     int i;
5226 
5227     CoInitialize(NULL);
5228 
5229     for (i = 0; i < ARRAY_SIZE(folders); i++)
5230     {
5231         IShellFolder2 *folder;
5232         GUID guid;
5233 
5234         hr = CoCreateInstance(folders[i], NULL, CLSCTX_INPROC_SERVER, &IID_IShellFolder2, (void **)&folder);
5235         if (hr != S_OK)
5236         {
5237             win_skip("Failed to create folder %s, hr %#x.\n", wine_dbgstr_guid(folders[i]), hr);
5238             continue;
5239         }
5240 
5241         if (0)
5242         {
5243             /* crashes on XP */
5244             hr = IShellFolder2_GetDefaultSearchGUID(folder, NULL);
5245             ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
5246         }
5247 
5248         memcpy(&guid, &CLSID_MyComputer, sizeof(guid));
5249         hr = IShellFolder2_GetDefaultSearchGUID(folder, &guid);
5250         ok(hr == E_NOTIMPL || broken(hr == S_OK) /* Method was last supported on XP */, "Unexpected hr %#x.\n", hr);
5251         if (hr == E_NOTIMPL)
5252             ok(IsEqualGUID(&guid, &CLSID_MyComputer), "Unexpected guid %s.\n", wine_dbgstr_guid(&guid));
5253 
5254         IShellFolder2_Release(folder);
5255     }
5256 
5257     CoUninitialize();
5258 }
5259 
test_SHLimitInputEdit(void)5260 static void test_SHLimitInputEdit(void)
5261 {
5262     IShellFolder *desktop;
5263     HRESULT hr;
5264     HWND hwnd;
5265 
5266     hr = SHGetDesktopFolder(&desktop);
5267     ok(hr == S_OK, "Failed to get desktop folder, hr %#x.\n", hr);
5268 
5269     hr = SHLimitInputEdit(NULL, desktop);
5270 todo_wine
5271     ok(hr == E_FAIL, "Unexpected hr %#x.\n", hr);
5272 
5273     hwnd = CreateWindowA("EDIT", NULL, WS_VISIBLE, 0, 0, 100, 30, NULL, NULL, NULL, NULL);
5274     ok(hwnd != NULL, "Failed to create Edit control.\n");
5275 
5276     hr = SHLimitInputEdit(hwnd, desktop);
5277 todo_wine
5278     ok(hr == S_OK, "Failed to set input limits, hr %#x.\n", hr);
5279 
5280     hr = SHLimitInputEdit(hwnd, desktop);
5281 todo_wine
5282     ok(hr == S_OK, "Failed to set input limits, hr %#x.\n", hr);
5283 
5284     DestroyWindow(hwnd);
5285     IShellFolder_Release(desktop);
5286 }
5287 
test_SHGetSetFolderCustomSettings(void)5288 static void test_SHGetSetFolderCustomSettings(void)
5289 {
5290     HRESULT hr;
5291     SHFOLDERCUSTOMSETTINGS fcs;
5292     WCHAR pathW[MAX_PATH];
5293     WCHAR bufferW[MAX_PATH];
5294     WCHAR iconpathW[MAX_PATH];
5295     static const WCHAR somedirW[] = {'s','o','m','e','_','d','i','r',0};
5296     static const WCHAR iconW[] = {'\\','s','o','m','e','_','i','c','o','n','.','i','c','o',0};
5297     static const WCHAR desktop_iniW[] = {'\\','D','e','s','k','t','o','p','.','i','n','i',0};
5298 
5299     if (!pSHGetSetFolderCustomSettings)
5300     {
5301         win_skip("SHGetSetFolderCustomSetting not exported by name (only by ordinal) for version XP/win2003\n");
5302         return;
5303     }
5304 
5305     GetTempPathW(MAX_PATH, pathW);
5306     lstrcatW(pathW, somedirW);
5307     CreateDirectoryW(pathW, NULL);
5308 
5309     lstrcpyW(iconpathW, pathW);
5310     lstrcatW(iconpathW, iconW);
5311 
5312     memset(&fcs, 0, sizeof(fcs));
5313     fcs.dwSize = sizeof(fcs);
5314     fcs.dwMask = FCSM_ICONFILE;
5315     fcs.pszIconFile = iconpathW;
5316 
5317     hr = pSHGetSetFolderCustomSettings(&fcs, pathW, FCS_FORCEWRITE); /*creates and writes to a Desktop.ini*/
5318     ok(hr == S_OK, "Expected S_OK, got %#x\n", hr);
5319 
5320     memset(&fcs, 0, sizeof(fcs));
5321     fcs.dwSize = sizeof(fcs);
5322     fcs.dwMask = FCSM_ICONFILE;
5323     fcs.cchIconFile = MAX_PATH;
5324     fcs.pszIconFile = bufferW;
5325     bufferW[0] = 0;
5326 
5327     hr = pSHGetSetFolderCustomSettings(&fcs, pathW, FCS_READ);
5328     todo_wine ok(hr == S_OK, "Expected S_OK, got %#x\n", hr);
5329     todo_wine ok(!lstrcmpiW(iconpathW, fcs.pszIconFile), "Expected %s, got %s\n", wine_dbgstr_w(iconpathW), wine_dbgstr_w(fcs.pszIconFile));
5330 
5331     hr = pSHGetSetFolderCustomSettings(&fcs, NULL, FCS_READ);
5332     ok(hr == E_FAIL, "Expected E_FAIL, got %#x\n", hr);
5333 
5334     lstrcpyW(bufferW, pathW);
5335     lstrcatW(bufferW, desktop_iniW);
5336     DeleteFileW(bufferW);
5337     RemoveDirectoryW(pathW);
5338 }
5339 
START_TEST(shlfolder)5340 START_TEST(shlfolder)
5341 {
5342     init_function_pointers();
5343     /* if OleInitialize doesn't get called, ParseDisplayName returns
5344        CO_E_NOTINITIALIZED for malformed directory names */
5345     OleInitialize(NULL);
5346 
5347     test_ParseDisplayName();
5348     test_SHParseDisplayName();
5349     test_BindToObject();
5350     test_EnumObjects_and_CompareIDs();
5351     test_GetDisplayName();
5352     test_GetAttributesOf();
5353     test_SHGetPathFromIDList();
5354     test_CallForAttributes();
5355     test_FolderShortcut();
5356     test_ITEMIDLIST_format();
5357     test_SHGetFolderPathA();
5358     test_SHGetFolderPathAndSubDirA();
5359     test_LocalizedNames();
5360     test_SHCreateShellItem();
5361     test_SHCreateShellItemArray();
5362     test_ShellItemArrayEnumItems();
5363     test_desktop_IPersist();
5364     test_GetUIObject();
5365     test_SHSimpleIDListFromPath();
5366     test_ParseDisplayNamePBC();
5367     test_SHGetNameFromIDList();
5368     test_SHGetItemFromDataObject();
5369     test_SHGetIDListFromObject();
5370     test_SHGetItemFromObject();
5371     test_ShellItemCompare();
5372     test_SHChangeNotify(FALSE);
5373     test_SHChangeNotify(TRUE);
5374     test_ShellItemBindToHandler();
5375     test_ShellItemGetAttributes();
5376     test_ShellItemArrayGetAttributes();
5377     test_SHCreateDefaultContextMenu();
5378     test_DataObject();
5379     test_GetDefaultColumn();
5380     test_GetDefaultSearchGUID();
5381     test_SHLimitInputEdit();
5382     test_SHGetSetFolderCustomSettings();
5383 
5384     OleUninitialize();
5385 }
5386