shell32/tests: Fix compilation on systems that don't support nameless unions.
[wine] / dlls / shell32 / tests / shlfolder.c
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/test.h"
41
42 #include <initguid.h>
43 DEFINE_GUID(IID_IParentAndItem, 0xB3A4B685, 0xB685, 0x4805, 0x99,0xD9, 0x5D,0xEA,0xD2,0x87,0x32,0x36);
44
45 static IMalloc *ppM;
46
47 static HRESULT (WINAPI *pSHBindToParent)(LPCITEMIDLIST, REFIID, LPVOID*, LPCITEMIDLIST*);
48 static HRESULT (WINAPI *pSHGetFolderPathA)(HWND, int, HANDLE, DWORD, LPSTR);
49 static HRESULT (WINAPI *pSHGetFolderPathAndSubDirA)(HWND, int, HANDLE, DWORD, LPCSTR, LPSTR);
50 static BOOL (WINAPI *pSHGetPathFromIDListW)(LPCITEMIDLIST,LPWSTR);
51 static HRESULT (WINAPI *pSHGetSpecialFolderLocation)(HWND, int, LPITEMIDLIST *);
52 static BOOL (WINAPI *pSHGetSpecialFolderPathA)(HWND, LPSTR, int, BOOL);
53 static BOOL (WINAPI *pSHGetSpecialFolderPathW)(HWND, LPWSTR, int, BOOL);
54 static HRESULT (WINAPI *pStrRetToBufW)(STRRET*,LPCITEMIDLIST,LPWSTR,UINT);
55 static LPITEMIDLIST (WINAPI *pILFindLastID)(LPCITEMIDLIST);
56 static void (WINAPI *pILFree)(LPITEMIDLIST);
57 static BOOL (WINAPI *pILIsEqual)(LPCITEMIDLIST, LPCITEMIDLIST);
58 static HRESULT (WINAPI *pSHCreateItemFromIDList)(PCIDLIST_ABSOLUTE pidl, REFIID riid, void **ppv);
59 static HRESULT (WINAPI *pSHCreateItemFromParsingName)(PCWSTR,IBindCtx*,REFIID,void**);
60 static HRESULT (WINAPI *pSHCreateShellItem)(LPCITEMIDLIST,IShellFolder*,LPCITEMIDLIST,IShellItem**);
61 static HRESULT (WINAPI *pSHCreateShellItemArray)(LPCITEMIDLIST,IShellFolder*,UINT,LPCITEMIDLIST*,IShellItemArray**);
62 static HRESULT (WINAPI *pSHCreateShellItemArrayFromDataObject)(IDataObject*, REFIID, void **);
63 static HRESULT (WINAPI *pSHCreateShellItemArrayFromShellItem)(IShellItem*, REFIID, void **);
64 static LPITEMIDLIST (WINAPI *pILCombine)(LPCITEMIDLIST,LPCITEMIDLIST);
65 static HRESULT (WINAPI *pSHParseDisplayName)(LPCWSTR,IBindCtx*,LPITEMIDLIST*,SFGAOF,SFGAOF*);
66 static LPITEMIDLIST (WINAPI *pSHSimpleIDListFromPathAW)(LPCVOID);
67 static HRESULT (WINAPI *pSHGetNameFromIDList)(PCIDLIST_ABSOLUTE,SIGDN,PWSTR*);
68 static HRESULT (WINAPI *pSHGetItemFromDataObject)(IDataObject*,DATAOBJ_GET_ITEM_FLAGS,REFIID,void**);
69 static HRESULT (WINAPI *pSHGetIDListFromObject)(IUnknown*, PIDLIST_ABSOLUTE*);
70 static HRESULT (WINAPI *pSHGetItemFromObject)(IUnknown*,REFIID,void**);
71
72 static int strcmp_wa(LPCWSTR strw, const char *stra)
73 {
74     CHAR buf[512];
75     WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL);
76     return lstrcmpA(stra, buf);
77 }
78
79 static void init_function_pointers(void)
80 {
81     HMODULE hmod;
82     HRESULT hr;
83     void *ptr;
84
85     hmod = GetModuleHandleA("shell32.dll");
86
87 #define MAKEFUNC(f) (p##f = (void*)GetProcAddress(hmod, #f))
88     MAKEFUNC(SHBindToParent);
89     MAKEFUNC(SHCreateItemFromIDList);
90     MAKEFUNC(SHCreateItemFromParsingName);
91     MAKEFUNC(SHCreateShellItem);
92     MAKEFUNC(SHCreateShellItemArray);
93     MAKEFUNC(SHCreateShellItemArrayFromDataObject);
94     MAKEFUNC(SHCreateShellItemArrayFromShellItem);
95     MAKEFUNC(SHGetFolderPathA);
96     MAKEFUNC(SHGetFolderPathAndSubDirA);
97     MAKEFUNC(SHGetPathFromIDListW);
98     MAKEFUNC(SHGetSpecialFolderPathA);
99     MAKEFUNC(SHGetSpecialFolderPathW);
100     MAKEFUNC(SHGetSpecialFolderLocation);
101     MAKEFUNC(SHParseDisplayName);
102     MAKEFUNC(SHGetNameFromIDList);
103     MAKEFUNC(SHGetItemFromDataObject);
104     MAKEFUNC(SHGetIDListFromObject);
105     MAKEFUNC(SHGetItemFromObject);
106 #undef MAKEFUNC
107
108 #define MAKEFUNC_ORD(f, ord) (p##f = (void*)GetProcAddress(hmod, (LPSTR)(ord)))
109     MAKEFUNC_ORD(ILFindLastID, 16);
110     MAKEFUNC_ORD(ILIsEqual, 21);
111     MAKEFUNC_ORD(ILCombine, 25);
112     MAKEFUNC_ORD(ILFree, 155);
113     MAKEFUNC_ORD(SHSimpleIDListFromPathAW, 162);
114 #undef MAKEFUNC_ORD
115
116     /* test named exports */
117     ptr = GetProcAddress(hmod, "ILFree");
118     ok(broken(ptr == 0) || ptr != 0, "expected named export for ILFree\n");
119     if (ptr)
120     {
121 #define TESTNAMED(f) \
122     ptr = (void*)GetProcAddress(hmod, #f); \
123     ok(ptr != 0, "expected named export for " #f "\n");
124
125         TESTNAMED(ILAppendID);
126         TESTNAMED(ILClone);
127         TESTNAMED(ILCloneFirst);
128         TESTNAMED(ILCombine);
129         TESTNAMED(ILCreateFromPath);
130         TESTNAMED(ILCreateFromPathA);
131         TESTNAMED(ILCreateFromPathW);
132         TESTNAMED(ILFindChild);
133         TESTNAMED(ILFindLastID);
134         TESTNAMED(ILGetNext);
135         TESTNAMED(ILGetSize);
136         TESTNAMED(ILIsEqual);
137         TESTNAMED(ILIsParent);
138         TESTNAMED(ILRemoveLastID);
139         TESTNAMED(ILSaveToStream);
140 #undef TESTNAMED
141     }
142
143     hmod = GetModuleHandleA("shlwapi.dll");
144     pStrRetToBufW = (void*)GetProcAddress(hmod, "StrRetToBufW");
145
146     hr = SHGetMalloc(&ppM);
147     ok(hr == S_OK, "SHGetMalloc failed %08x\n", hr);
148 }
149
150 static void test_ParseDisplayName(void)
151 {
152     HRESULT hr;
153     IShellFolder *IDesktopFolder;
154     static const char *cNonExistDir1A = "c:\\nonexist_subdir";
155     static const char *cNonExistDir2A = "c:\\\\nonexist_subdir";
156     static const char *cInetTestA = "http:\\yyy";
157     static const char *cInetTest2A = "xx:yyy";
158     DWORD res;
159     WCHAR cTestDirW [MAX_PATH] = {0};
160     ITEMIDLIST *newPIDL;
161     BOOL bRes;
162
163     hr = SHGetDesktopFolder(&IDesktopFolder);
164     ok(hr == S_OK, "Expected SHGetDesktopFolder to return S_OK, got 0x%08x\n", hr);
165     if(hr != S_OK) return;
166
167     /* Tests crash on W2K and below (SHCreateShellItem available as of XP) */
168     if (pSHCreateShellItem)
169     {
170         /* null name and pidl */
171         hr = IShellFolder_ParseDisplayName(IDesktopFolder,
172             NULL, NULL, NULL, NULL, NULL, 0);
173         ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
174
175         /* null name */
176         newPIDL = (ITEMIDLIST*)0xdeadbeef;
177         hr = IShellFolder_ParseDisplayName(IDesktopFolder,
178             NULL, NULL, NULL, NULL, &newPIDL, 0);
179         ok(newPIDL == 0, "expected null, got %p\n", newPIDL);
180         ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
181     }
182     else
183         win_skip("Tests would crash on W2K and below\n");
184
185     MultiByteToWideChar(CP_ACP, 0, cInetTestA, -1, cTestDirW, MAX_PATH);
186     hr = IShellFolder_ParseDisplayName(IDesktopFolder,
187         NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
188     todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
189         "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
190     if (hr == S_OK)
191     {
192         ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
193            "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
194         IMalloc_Free(ppM, newPIDL);
195     }
196
197     MultiByteToWideChar(CP_ACP, 0, cInetTest2A, -1, cTestDirW, MAX_PATH);
198     hr = IShellFolder_ParseDisplayName(IDesktopFolder,
199         NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
200     todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
201         "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
202     if (hr == S_OK)
203     {
204         ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
205            "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
206         IMalloc_Free(ppM, newPIDL);
207     }
208
209     res = GetFileAttributesA(cNonExistDir1A);
210     if(res != INVALID_FILE_ATTRIBUTES)
211     {
212         skip("Test directory unexpectedly exists\n");
213         goto finished;
214     }
215
216     MultiByteToWideChar(CP_ACP, 0, cNonExistDir1A, -1, cTestDirW, MAX_PATH);
217     hr = IShellFolder_ParseDisplayName(IDesktopFolder, 
218         NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
219     ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL), 
220         "ParseDisplayName returned %08x, expected 80070002 or E_FAIL\n", hr);
221
222     res = GetFileAttributesA(cNonExistDir2A);
223     if(res != INVALID_FILE_ATTRIBUTES)
224     {
225         skip("Test directory unexpectedly exists\n");
226         goto finished;
227     }
228
229     MultiByteToWideChar(CP_ACP, 0, cNonExistDir2A, -1, cTestDirW, MAX_PATH);
230     hr = IShellFolder_ParseDisplayName(IDesktopFolder, 
231         NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
232     ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL) || (hr == E_INVALIDARG), 
233         "ParseDisplayName returned %08x, expected 80070002, E_FAIL or E_INVALIDARG\n", hr);
234
235     /* I thought that perhaps the DesktopFolder's ParseDisplayName would recognize the
236      * path corresponding to CSIDL_PERSONAL and return a CLSID_MyDocuments PIDL. Turns
237      * out it doesn't. The magic seems to happen in the file dialogs, then. */
238     if (!pSHGetSpecialFolderPathW || !pILFindLastID)
239     {
240         win_skip("SHGetSpecialFolderPathW and/or ILFindLastID are not available\n");
241         goto finished;
242     }
243
244     bRes = pSHGetSpecialFolderPathW(NULL, cTestDirW, CSIDL_PERSONAL, FALSE);
245     ok(bRes, "SHGetSpecialFolderPath(CSIDL_PERSONAL) failed! %u\n", GetLastError());
246     if (!bRes) goto finished;
247
248     hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
249     ok(hr == S_OK, "DesktopFolder->ParseDisplayName failed. hr = %08x.\n", hr);
250     if (hr != S_OK) goto finished;
251
252     ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x31 ||
253        pILFindLastID(newPIDL)->mkid.abID[0] == 0xb1, /* Win98 */
254        "Last pidl should be of type PT_FOLDER or PT_IESPECIAL2, but is: %02x\n",
255        pILFindLastID(newPIDL)->mkid.abID[0]);
256     IMalloc_Free(ppM, newPIDL);
257     
258 finished:
259     IShellFolder_Release(IDesktopFolder);
260 }
261
262 /* creates a file with the specified name for tests */
263 static void CreateTestFile(const CHAR *name)
264 {
265     HANDLE file;
266     DWORD written;
267
268     file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
269     if (file != INVALID_HANDLE_VALUE)
270     {
271         WriteFile(file, name, strlen(name), &written, NULL);
272         WriteFile(file, "\n", strlen("\n"), &written, NULL);
273         CloseHandle(file);
274     }
275 }
276
277
278 /* initializes the tests */
279 static void CreateFilesFolders(void)
280 {
281     CreateDirectoryA(".\\testdir", NULL);
282     CreateDirectoryA(".\\testdir\\test.txt", NULL);
283     CreateTestFile  (".\\testdir\\test1.txt ");
284     CreateTestFile  (".\\testdir\\test2.txt ");
285     CreateTestFile  (".\\testdir\\test3.txt ");
286     CreateDirectoryA(".\\testdir\\testdir2 ", NULL);
287     CreateDirectoryA(".\\testdir\\testdir2\\subdir", NULL);
288 }
289
290 /* cleans after tests */
291 static void Cleanup(void)
292 {
293     DeleteFileA(".\\testdir\\test1.txt");
294     DeleteFileA(".\\testdir\\test2.txt");
295     DeleteFileA(".\\testdir\\test3.txt");
296     RemoveDirectoryA(".\\testdir\\test.txt");
297     RemoveDirectoryA(".\\testdir\\testdir2\\subdir");
298     RemoveDirectoryA(".\\testdir\\testdir2");
299     RemoveDirectoryA(".\\testdir");
300 }
301
302
303 /* perform test */
304 static void test_EnumObjects(IShellFolder *iFolder)
305 {
306     IEnumIDList *iEnumList;
307     LPITEMIDLIST newPIDL, idlArr[10];
308     ULONG NumPIDLs;
309     int i=0, j;
310     HRESULT hr;
311
312     static const WORD iResults [5][5] =
313     {
314         { 0,-1,-1,-1,-1},
315         { 1, 0,-1,-1,-1},
316         { 1, 1, 0,-1,-1},
317         { 1, 1, 1, 0,-1},
318         { 1, 1, 1, 1, 0}
319     };
320
321 #define SFGAO_testfor SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | SFGAO_CAPABILITYMASK
322     /* Don't test for SFGAO_HASSUBFOLDER since we return real state and native cached */
323     static const ULONG attrs[5] =
324     {
325         SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
326         SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
327         SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
328         SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
329         SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
330     };
331
332     hr = IShellFolder_EnumObjects(iFolder, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &iEnumList);
333     ok(hr == S_OK, "EnumObjects failed %08x\n", hr);
334
335     /* This is to show that, contrary to what is said on MSDN, on IEnumIDList::Next,
336      * the filesystem shellfolders return S_OK even if less than 'celt' items are
337      * returned (in contrast to S_FALSE). We have to do it in a loop since WinXP
338      * only ever returns a single entry per call. */
339     while (IEnumIDList_Next(iEnumList, 10-i, &idlArr[i], &NumPIDLs) == S_OK) 
340         i += NumPIDLs;
341     ok (i == 5, "i: %d\n", i);
342
343     hr = IEnumIDList_Release(iEnumList);
344     ok(hr == S_OK, "IEnumIDList_Release failed %08x\n", hr);
345     
346     /* Sort them first in case of wrong order from system */
347     for (i=0;i<5;i++) for (j=0;j<5;j++)
348         if ((SHORT)IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]) < 0)
349         {
350             newPIDL = idlArr[i];
351             idlArr[i] = idlArr[j];
352             idlArr[j] = newPIDL;
353         }
354             
355     for (i=0;i<5;i++) for (j=0;j<5;j++)
356     {
357         hr = IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]);
358         ok(hr == iResults[i][j], "Got %x expected [%d]-[%d]=%x\n", hr, i, j, iResults[i][j]);
359     }
360
361
362     for (i = 0; i < 5; i++)
363     {
364         SFGAOF flags;
365 #define SFGAO_VISTA SFGAO_DROPTARGET | SFGAO_CANLINK | SFGAO_CANCOPY
366         /* Native returns all flags no matter what we ask for */
367         flags = SFGAO_CANCOPY;
368         hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
369         flags &= SFGAO_testfor;
370         ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
371         ok(flags == (attrs[i]) ||
372            flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR) || /* Win9x, NT4 */
373            flags == ((attrs[i] & ~SFGAO_CAPABILITYMASK) | SFGAO_VISTA), /* Vista and higher */
374            "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
375
376         flags = SFGAO_testfor;
377         hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
378         flags &= SFGAO_testfor;
379         ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
380         ok(flags == attrs[i] ||
381            flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR), /* Win9x, NT4 */
382            "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
383     }
384
385     for (i=0;i<5;i++)
386         IMalloc_Free(ppM, idlArr[i]);
387 }
388
389 static void test_BindToObject(void)
390 {
391     HRESULT hr;
392     UINT cChars;
393     IShellFolder *psfDesktop, *psfChild, *psfMyComputer, *psfSystemDir;
394     SHITEMID emptyitem = { 0, { 0 } };
395     LPITEMIDLIST pidlMyComputer, pidlSystemDir, pidlEmpty = (LPITEMIDLIST)&emptyitem;
396     WCHAR wszSystemDir[MAX_PATH];
397     char szSystemDir[MAX_PATH];
398     WCHAR wszMyComputer[] = { 
399         ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
400         'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
401
402     /* The following tests shows that BindToObject should fail with E_INVALIDARG if called
403      * with an empty pidl. This is tested for Desktop, MyComputer and the FS ShellFolder
404      */
405     hr = SHGetDesktopFolder(&psfDesktop);
406     ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
407     if (hr != S_OK) return;
408     
409     hr = IShellFolder_BindToObject(psfDesktop, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
410     ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
411
412     hr = IShellFolder_BindToObject(psfDesktop, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
413     ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
414
415     hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
416     ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
417     if (hr != S_OK) {
418         IShellFolder_Release(psfDesktop);
419         return;
420     }
421     
422     hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
423     ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
424     IShellFolder_Release(psfDesktop);
425     IMalloc_Free(ppM, pidlMyComputer);
426     if (hr != S_OK) return;
427
428     hr = IShellFolder_BindToObject(psfMyComputer, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
429     ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
430
431 if (0)
432 {
433     /* this call segfaults on 98SE */
434     hr = IShellFolder_BindToObject(psfMyComputer, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
435     ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
436 }
437
438     cChars = GetSystemDirectoryA(szSystemDir, MAX_PATH);
439     ok (cChars > 0 && cChars < MAX_PATH, "GetSystemDirectoryA failed! LastError: %u\n", GetLastError());
440     if (cChars == 0 || cChars >= MAX_PATH) {
441         IShellFolder_Release(psfMyComputer);
442         return;
443     }
444     MultiByteToWideChar(CP_ACP, 0, szSystemDir, -1, wszSystemDir, MAX_PATH);
445     
446     hr = IShellFolder_ParseDisplayName(psfMyComputer, NULL, NULL, wszSystemDir, NULL, &pidlSystemDir, NULL);
447     ok (hr == S_OK, "MyComputers's ParseDisplayName failed to parse the SystemDirectory! hr = %08x\n", hr);
448     if (hr != S_OK) {
449         IShellFolder_Release(psfMyComputer);
450         return;
451     }
452
453     hr = IShellFolder_BindToObject(psfMyComputer, pidlSystemDir, NULL, &IID_IShellFolder, (LPVOID*)&psfSystemDir);
454     ok (hr == S_OK, "MyComputer failed to bind to a FileSystem ShellFolder! hr = %08x\n", hr);
455     IShellFolder_Release(psfMyComputer);
456     IMalloc_Free(ppM, pidlSystemDir);
457     if (hr != S_OK) return;
458
459     hr = IShellFolder_BindToObject(psfSystemDir, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
460     ok (hr == E_INVALIDARG, 
461         "FileSystem ShellFolder's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
462
463 if (0)
464 {
465     /* this call segfaults on 98SE */
466     hr = IShellFolder_BindToObject(psfSystemDir, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
467     ok (hr == E_INVALIDARG,
468         "FileSystem ShellFolder's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
469 }
470
471     IShellFolder_Release(psfSystemDir);
472 }
473
474 /* Based on PathAddBackslashW from dlls/shlwapi/path.c */
475 static LPWSTR myPathAddBackslashW( LPWSTR lpszPath )
476 {
477   size_t iLen;
478
479   if (!lpszPath || (iLen = lstrlenW(lpszPath)) >= MAX_PATH)
480     return NULL;
481
482   if (iLen)
483   {
484     lpszPath += iLen;
485     if (lpszPath[-1] != '\\')
486     {
487       *lpszPath++ = '\\';
488       *lpszPath = '\0';
489     }
490   }
491   return lpszPath;
492 }
493
494 static void test_GetDisplayName(void)
495 {
496     BOOL result;
497     HRESULT hr;
498     HANDLE hTestFile;
499     WCHAR wszTestFile[MAX_PATH], wszTestFile2[MAX_PATH];
500     char szTestFile[MAX_PATH], szTestDir[MAX_PATH];
501     DWORD attr;
502     STRRET strret;
503     LPSHELLFOLDER psfDesktop, psfPersonal;
504     IUnknown *psfFile;
505     SHITEMID emptyitem = { 0, { 0 } };
506     LPITEMIDLIST pidlTestFile, pidlEmpty = (LPITEMIDLIST)&emptyitem;
507     LPCITEMIDLIST pidlLast;
508     static const CHAR szFileName[] = "winetest.foo";
509     static const WCHAR wszFileName[] = { 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
510     static const WCHAR wszDirName[] = { 'w','i','n','e','t','e','s','t',0 };
511
512     /* I'm trying to figure if there is a functional difference between calling
513      * SHGetPathFromIDListW and calling GetDisplayNameOf(SHGDN_FORPARSING) after
514      * binding to the shellfolder. One thing I thought of was that perhaps 
515      * SHGetPathFromIDListW would be able to get the path to a file, which does
516      * not exist anymore, while the other method wouldn't. It turns out there's
517      * no functional difference in this respect.
518      */
519
520     if(!pSHGetSpecialFolderPathA) {
521         win_skip("SHGetSpecialFolderPathA is not available\n");
522         return;
523     }
524
525     /* First creating a directory in MyDocuments and a file in this directory. */
526     result = pSHGetSpecialFolderPathA(NULL, szTestDir, CSIDL_PERSONAL, FALSE);
527     ok(result, "SHGetSpecialFolderPathA failed! Last error: %u\n", GetLastError());
528     if (!result) return;
529
530     /* Use ANSI file functions so this works on Windows 9x */
531     lstrcatA(szTestDir, "\\winetest");
532     CreateDirectoryA(szTestDir, NULL);
533     attr=GetFileAttributesA(szTestDir);
534     if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY))
535     {
536         ok(0, "unable to create the '%s' directory\n", szTestDir);
537         return;
538     }
539
540     lstrcpyA(szTestFile, szTestDir);
541     lstrcatA(szTestFile, "\\");
542     lstrcatA(szTestFile, szFileName);
543     hTestFile = CreateFileA(szTestFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
544     ok((hTestFile != INVALID_HANDLE_VALUE), "CreateFileA failed! Last error: %u\n", GetLastError());
545     if (hTestFile == INVALID_HANDLE_VALUE) return;
546     CloseHandle(hTestFile);
547
548     /* Getting an itemidlist for the file. */
549     hr = SHGetDesktopFolder(&psfDesktop);
550     ok(hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
551     if (hr != S_OK) return;
552
553     MultiByteToWideChar(CP_ACP, 0, szTestFile, -1, wszTestFile, MAX_PATH);
554
555     hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
556     ok(hr == S_OK, "Desktop->ParseDisplayName failed! hr = %08x\n", hr);
557     if (hr != S_OK) {
558         IShellFolder_Release(psfDesktop);
559         return;
560     }
561
562     pidlLast = pILFindLastID(pidlTestFile);
563     ok(pidlLast->mkid.cb >=76 ||
564         broken(pidlLast->mkid.cb == 28) || /* W2K */
565         broken(pidlLast->mkid.cb == 40), /* Win9x, WinME */
566         "Expected pidl length of at least 76, got %d.\n", pidlLast->mkid.cb);
567     if (pidlLast->mkid.cb >= 28) {
568         ok(!lstrcmpA((CHAR*)&pidlLast->mkid.abID[12], szFileName),
569             "Filename should be stored as ansi-string at this position!\n");
570     }
571     /* WinXP and up store the filenames as both ANSI and UNICODE in the pidls */
572     if (pidlLast->mkid.cb >= 76) {
573         ok(!lstrcmpW((WCHAR*)&pidlLast->mkid.abID[46], wszFileName) ||
574             (pidlLast->mkid.cb >= 94 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[64], wszFileName)) ||  /* Vista */
575             (pidlLast->mkid.cb >= 98 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[68], wszFileName)), /* Win7 */
576             "Filename should be stored as wchar-string at this position!\n");
577     }
578     
579     /* It seems as if we cannot bind to regular files on windows, but only directories. 
580      */
581     hr = IShellFolder_BindToObject(psfDesktop, pidlTestFile, NULL, &IID_IUnknown, (VOID**)&psfFile);
582     todo_wine
583     ok (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
584         hr == E_NOTIMPL || /* Vista */
585         broken(hr == S_OK), /* Win9x, W2K */
586         "hr = %08x\n", hr);
587     if (hr == S_OK) {
588         IShellFolder_Release(psfFile);
589     }
590
591     if (!pSHBindToParent)
592     {
593         win_skip("SHBindToParent is missing\n");
594         DeleteFileA(szTestFile);
595         RemoveDirectoryA(szTestDir);
596         return;
597     }
598   
599     /* Some tests for IShellFolder::SetNameOf */
600     if (pSHGetFolderPathAndSubDirA)
601     {
602         hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
603         ok(hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
604         if (hr == S_OK) {
605             /* It's ok to use this fixed path. Call will fail anyway. */
606             WCHAR wszAbsoluteFilename[] = { 'C',':','\\','w','i','n','e','t','e','s','t', 0 };
607             LPITEMIDLIST pidlNew;
608
609             /* The pidl returned through the last parameter of SetNameOf is a simple one. */
610             hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlLast, wszDirName, SHGDN_NORMAL, &pidlNew);
611             ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
612             if (hr == S_OK)
613             {
614                 ok (((LPITEMIDLIST)((LPBYTE)pidlNew+pidlNew->mkid.cb))->mkid.cb == 0,
615                     "pidl returned from SetNameOf should be simple!\n");
616
617                 /* Passing an absolute path to SetNameOf fails. The HRESULT code indicates that SetNameOf
618                  * is implemented on top of SHFileOperation in WinXP. */
619                 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszAbsoluteFilename,
620                         SHGDN_FORPARSING, NULL);
621                 ok (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED), "SetNameOf succeeded! hr = %08x\n", hr);
622
623                 /* Rename the file back to its original name. SetNameOf ignores the fact, that the
624                  * SHGDN flags specify an absolute path. */
625                 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszFileName, SHGDN_FORPARSING, NULL);
626                 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
627
628                 pILFree(pidlNew);
629             }
630
631             IShellFolder_Release(psfPersonal);
632         }
633     }
634     else
635         win_skip("Avoid needs of interaction on Win2k\n");
636
637     /* Deleting the file and the directory */
638     DeleteFileA(szTestFile);
639     RemoveDirectoryA(szTestDir);
640
641     /* SHGetPathFromIDListW still works, although the file is not present anymore. */
642     if (pSHGetPathFromIDListW)
643     {
644         result = pSHGetPathFromIDListW(pidlTestFile, wszTestFile2);
645         ok (result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
646         ok (!lstrcmpiW(wszTestFile, wszTestFile2), "SHGetPathFromIDListW returns incorrect path!\n");
647     }
648
649     /* SHBindToParent fails, if called with a NULL PIDL. */
650     hr = pSHBindToParent(NULL, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
651     ok (hr != S_OK, "SHBindToParent(NULL) should fail!\n");
652
653     /* But it succeeds with an empty PIDL. */
654     hr = pSHBindToParent(pidlEmpty, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
655     ok (hr == S_OK, "SHBindToParent(empty PIDL) should succeed! hr = %08x\n", hr);
656     ok (pidlLast == pidlEmpty, "The last element of an empty PIDL should be the PIDL itself!\n");
657     if (hr == S_OK)
658         IShellFolder_Release(psfPersonal);
659     
660     /* Binding to the folder and querying the display name of the file also works. */
661     hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast); 
662     ok (hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
663     if (hr != S_OK) {
664         IShellFolder_Release(psfDesktop);
665         return;
666     }
667
668     /* This test shows that Windows doesn't allocate a new pidlLast, but returns a pointer into 
669      * pidlTestFile (In accordance with MSDN). */
670     ok (pILFindLastID(pidlTestFile) == pidlLast, 
671                                 "SHBindToParent doesn't return the last id of the pidl param!\n");
672     
673     hr = IShellFolder_GetDisplayNameOf(psfPersonal, pidlLast, SHGDN_FORPARSING, &strret);
674     ok (hr == S_OK, "Personal->GetDisplayNameOf failed! hr = %08x\n", hr);
675     if (hr != S_OK) {
676         IShellFolder_Release(psfDesktop);
677         IShellFolder_Release(psfPersonal);
678         return;
679     }
680
681     if (pStrRetToBufW)
682     {
683         hr = pStrRetToBufW(&strret, pidlLast, wszTestFile2, MAX_PATH);
684         ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
685         ok (!lstrcmpiW(wszTestFile, wszTestFile2), "GetDisplayNameOf returns incorrect path!\n");
686     }
687     
688     ILFree(pidlTestFile);
689     IShellFolder_Release(psfDesktop);
690     IShellFolder_Release(psfPersonal);
691 }
692
693 static void test_CallForAttributes(void)
694 {
695     HKEY hKey;
696     LONG lResult;
697     HRESULT hr;
698     DWORD dwSize;
699     LPSHELLFOLDER psfDesktop;
700     LPITEMIDLIST pidlMyDocuments;
701     DWORD dwAttributes, dwCallForAttributes, dwOrigAttributes, dwOrigCallForAttributes;
702     static const WCHAR wszAttributes[] = { 'A','t','t','r','i','b','u','t','e','s',0 };
703     static const WCHAR wszCallForAttributes[] = { 
704         'C','a','l','l','F','o','r','A','t','t','r','i','b','u','t','e','s',0 };
705     static const WCHAR wszMyDocumentsKey[] = {
706         'C','L','S','I','D','\\','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-',
707         '1','1','D','0','-','9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',
708         '\\','S','h','e','l','l','F','o','l','d','e','r',0 };
709     WCHAR wszMyDocuments[] = {
710         ':',':','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-','1','1','D','0','-',
711         '9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',0 };
712     
713     /* For the root of a namespace extension, the attributes are not queried by binding
714      * to the object and calling GetAttributesOf. Instead, the attributes are read from 
715      * the registry value HKCR/CLSID/{...}/ShellFolder/Attributes. This is documented on MSDN.
716      *
717      * The MyDocuments shellfolder on WinXP has a HKCR/CLSID/{...}/ShellFolder/CallForAttributes
718      * value. It seems that if the folder is queried for one of the flags set in CallForAttributes,
719      * the shell does bind to the folder object and calls GetAttributesOf. This is not documented
720      * on MSDN. This test is meant to document the observed behaviour on WinXP SP2.
721      */
722     hr = SHGetDesktopFolder(&psfDesktop);
723     ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
724     if (hr != S_OK) return;
725     
726     hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyDocuments, NULL, 
727                                        &pidlMyDocuments, NULL);
728     ok (hr == S_OK ||
729         broken(hr == E_INVALIDARG), /* Win95, NT4 */
730         "Desktop's ParseDisplayName failed to parse MyDocuments's CLSID! hr = %08x\n", hr);
731     if (hr != S_OK) {
732         IShellFolder_Release(psfDesktop);
733         return;
734     }
735
736     dwAttributes = 0xffffffff;
737     hr = IShellFolder_GetAttributesOf(psfDesktop, 1, 
738                                       (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
739     ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
740
741     /* We need the following setup (as observed on WinXP SP2), for the tests to make sense. */
742     ok (dwAttributes & SFGAO_FILESYSTEM, "SFGAO_FILESYSTEM attribute is not set for MyDocuments!\n");
743     ok (!(dwAttributes & SFGAO_ISSLOW), "SFGAO_ISSLOW attribute is set for MyDocuments!\n");
744     ok (!(dwAttributes & SFGAO_GHOSTED), "SFGAO_GHOSTED attribute is set for MyDocuments!\n");
745
746     /* We don't have the MyDocuments shellfolder in wine yet, and thus we don't have the registry
747      * key. So the test will return at this point, if run on wine. 
748      */
749     lResult = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszMyDocumentsKey, 0, KEY_WRITE|KEY_READ, &hKey);
750     ok (lResult == ERROR_SUCCESS ||
751         lResult == ERROR_ACCESS_DENIED,
752         "RegOpenKeyEx failed! result: %08x\n", lResult);
753     if (lResult != ERROR_SUCCESS) {
754         if (lResult == ERROR_ACCESS_DENIED)
755             skip("Not enough rights to open the registry key\n");
756         IMalloc_Free(ppM, pidlMyDocuments);
757         IShellFolder_Release(psfDesktop);
758         return;
759     }
760     
761     /* Query MyDocuments' Attributes value, to be able to restore it later. */
762     dwSize = sizeof(DWORD);
763     lResult = RegQueryValueExW(hKey, wszAttributes, NULL, NULL, (LPBYTE)&dwOrigAttributes, &dwSize);
764     ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
765     if (lResult != ERROR_SUCCESS) {
766         RegCloseKey(hKey);
767         IMalloc_Free(ppM, pidlMyDocuments);
768         IShellFolder_Release(psfDesktop);
769         return;
770     }
771
772     /* Query MyDocuments' CallForAttributes value, to be able to restore it later. */
773     dwSize = sizeof(DWORD);
774     lResult = RegQueryValueExW(hKey, wszCallForAttributes, NULL, NULL, 
775                               (LPBYTE)&dwOrigCallForAttributes, &dwSize);
776     ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
777     if (lResult != ERROR_SUCCESS) {
778         RegCloseKey(hKey);
779         IMalloc_Free(ppM, pidlMyDocuments);
780         IShellFolder_Release(psfDesktop);
781         return;
782     }
783     
784     /* Define via the Attributes value that MyDocuments attributes are SFGAO_ISSLOW and 
785      * SFGAO_GHOSTED and that MyDocuments should be called for the SFGAO_ISSLOW and
786      * SFGAO_FILESYSTEM attributes. */
787     dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED;
788     RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwAttributes, sizeof(DWORD));
789     dwCallForAttributes = SFGAO_ISSLOW|SFGAO_FILESYSTEM;
790     RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD, 
791                    (LPBYTE)&dwCallForAttributes, sizeof(DWORD));
792
793     /* Although it is not set in CallForAttributes, the SFGAO_GHOSTED flag is reset by 
794      * GetAttributesOf. It seems that once there is a single attribute queried, for which
795      * CallForAttributes is set, all flags are taken from the GetAttributesOf call and
796      * the flags in Attributes are ignored. 
797      */
798     dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED|SFGAO_FILESYSTEM;
799     hr = IShellFolder_GetAttributesOf(psfDesktop, 1, 
800                                       (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
801     ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
802     if (hr == S_OK)
803         ok (dwAttributes == SFGAO_FILESYSTEM, 
804             "Desktop->GetAttributes(MyDocuments) returned unexpected attributes: %08x\n", 
805             dwAttributes);
806
807     /* Restore MyDocuments' original Attributes and CallForAttributes registry values */
808     RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwOrigAttributes, sizeof(DWORD));
809     RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD, 
810                    (LPBYTE)&dwOrigCallForAttributes, sizeof(DWORD));
811     RegCloseKey(hKey);
812     IMalloc_Free(ppM, pidlMyDocuments);
813     IShellFolder_Release(psfDesktop);
814 }
815
816 static void test_GetAttributesOf(void) 
817 {
818     HRESULT hr;
819     LPSHELLFOLDER psfDesktop, psfMyComputer;
820     SHITEMID emptyitem = { 0, { 0 } };
821     LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
822     LPITEMIDLIST pidlMyComputer;
823     DWORD dwFlags;
824     static const DWORD desktopFlags[] = {
825         /* WinXP */
826         SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSANCESTOR |
827         SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
828         /* Win2k */
829         SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_STREAM | SFGAO_FILESYSANCESTOR |
830         SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
831         /* WinMe, Win9x, WinNT*/
832         SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSANCESTOR |
833         SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
834     };
835     static const DWORD myComputerFlags[] = {
836         /* WinXP */
837         SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
838         SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
839         /* Win2k */
840         SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_STREAM |
841         SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
842         /* WinMe, Win9x, WinNT */
843         SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
844         SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
845         /* Win95, WinNT when queried directly */
846         SFGAO_CANLINK | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
847         SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
848     };
849     WCHAR wszMyComputer[] = { 
850         ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
851         'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
852     char  cCurrDirA [MAX_PATH] = {0};
853     WCHAR cCurrDirW [MAX_PATH];
854     static WCHAR cTestDirW[] = {'t','e','s','t','d','i','r',0};
855     IShellFolder *IDesktopFolder, *testIShellFolder;
856     ITEMIDLIST *newPIDL;
857     int len, i;
858     BOOL foundFlagsMatch;
859
860     hr = SHGetDesktopFolder(&psfDesktop);
861     ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
862     if (hr != S_OK) return;
863
864     /* The Desktop attributes can be queried with a single empty itemidlist, .. */
865     dwFlags = 0xffffffff;
866     hr = IShellFolder_GetAttributesOf(psfDesktop, 1, &pidlEmpty, &dwFlags);
867     ok (hr == S_OK, "Desktop->GetAttributesOf(empty pidl) failed! hr = %08x\n", hr);
868     for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
869          i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
870     {
871         if (desktopFlags[i] == dwFlags)
872             foundFlagsMatch = TRUE;
873     }
874     ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
875
876     /* .. or with no itemidlist at all. */
877     dwFlags = 0xffffffff;
878     hr = IShellFolder_GetAttributesOf(psfDesktop, 0, NULL, &dwFlags);
879     ok (hr == S_OK, "Desktop->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
880     for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
881          i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
882     {
883         if (desktopFlags[i] == dwFlags)
884             foundFlagsMatch = TRUE;
885     }
886     ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
887    
888     /* Testing the attributes of the MyComputer shellfolder */
889     hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
890     ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
891     if (hr != S_OK) {
892         IShellFolder_Release(psfDesktop);
893         return;
894     }
895
896     /* Windows sets the SFGAO_CANLINK flag, when MyComputer is queried via the Desktop
897      * folder object. It doesn't do this, if MyComputer is queried directly (see below).
898      */
899     dwFlags = 0xffffffff;
900     hr = IShellFolder_GetAttributesOf(psfDesktop, 1, (LPCITEMIDLIST*)&pidlMyComputer, &dwFlags);
901     ok (hr == S_OK, "Desktop->GetAttributesOf(MyComputer) failed! hr = %08x\n", hr);
902     for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
903          i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
904     {
905         if ((myComputerFlags[i] | SFGAO_CANLINK) == dwFlags)
906             foundFlagsMatch = TRUE;
907     }
908     todo_wine
909     ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
910
911     hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
912     ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
913     IShellFolder_Release(psfDesktop);
914     IMalloc_Free(ppM, pidlMyComputer);
915     if (hr != S_OK) return;
916
917     hr = IShellFolder_GetAttributesOf(psfMyComputer, 1, &pidlEmpty, &dwFlags);
918     todo_wine
919     ok (hr == E_INVALIDARG ||
920         broken(hr == S_OK), /* W2K and earlier */
921         "MyComputer->GetAttributesOf(emtpy pidl) should fail! hr = %08x\n", hr);
922
923     dwFlags = 0xffffffff;
924     hr = IShellFolder_GetAttributesOf(psfMyComputer, 0, NULL, &dwFlags);
925     ok (hr == S_OK, "MyComputer->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
926     for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
927          i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
928     {
929         if (myComputerFlags[i] == dwFlags)
930             foundFlagsMatch = TRUE;
931     }
932     todo_wine
933     ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
934
935     IShellFolder_Release(psfMyComputer);
936
937     GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
938     len = lstrlenA(cCurrDirA);
939
940     if (len == 0) {
941         win_skip("GetCurrentDirectoryA returned empty string. Skipping test_GetAttributesOf\n");
942         return;
943     }
944     if (len > 3 && cCurrDirA[len-1] == '\\')
945         cCurrDirA[len-1] = 0;
946
947     /* create test directory */
948     CreateFilesFolders();
949
950     MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
951  
952     hr = SHGetDesktopFolder(&IDesktopFolder);
953     ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
954
955     hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
956     ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
957
958     hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
959     ok(hr == S_OK, "BindToObject failed %08x\n", hr);
960
961     IMalloc_Free(ppM, newPIDL);
962
963     /* get relative PIDL */
964     hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
965     ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
966
967     /* test the shell attributes of the test directory using the relative PIDL */
968     dwFlags = SFGAO_FOLDER;
969     hr = IShellFolder_GetAttributesOf(testIShellFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
970     ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
971     ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for relative PIDL: %08x\n", dwFlags);
972
973     /* free memory */
974     IMalloc_Free(ppM, newPIDL);
975
976     /* append testdirectory name to path */
977     if (cCurrDirA[len-1] == '\\')
978         cCurrDirA[len-1] = 0;
979     lstrcatA(cCurrDirA, "\\testdir");
980     MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
981
982     hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
983     ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
984
985     /* test the shell attributes of the test directory using the absolute PIDL */
986     dwFlags = SFGAO_FOLDER;
987     hr = IShellFolder_GetAttributesOf(IDesktopFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
988     ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
989     ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for absolute PIDL: %08x\n", dwFlags);
990
991     /* free memory */
992     IMalloc_Free(ppM, newPIDL);
993
994     IShellFolder_Release(testIShellFolder);
995
996     Cleanup();
997
998     IShellFolder_Release(IDesktopFolder);
999 }
1000
1001 static void test_SHGetPathFromIDList(void)
1002 {
1003     SHITEMID emptyitem = { 0, { 0 } };
1004     LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
1005     LPITEMIDLIST pidlMyComputer;
1006     WCHAR wszPath[MAX_PATH], wszDesktop[MAX_PATH];
1007     BOOL result;
1008     HRESULT hr;
1009     LPSHELLFOLDER psfDesktop;
1010     WCHAR wszMyComputer[] = { 
1011         ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
1012         'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
1013     WCHAR wszFileName[MAX_PATH];
1014     LPITEMIDLIST pidlTestFile;
1015     HANDLE hTestFile;
1016     STRRET strret;
1017     static WCHAR wszTestFile[] = {
1018         'w','i','n','e','t','e','s','t','.','f','o','o',0 };
1019     LPITEMIDLIST pidlPrograms;
1020
1021     if(!pSHGetPathFromIDListW || !pSHGetSpecialFolderPathW)
1022     {
1023         win_skip("SHGetPathFromIDListW() or SHGetSpecialFolderPathW() is missing\n");
1024         return;
1025     }
1026
1027     /* Calling SHGetPathFromIDListW with no pidl should return the empty string */
1028     wszPath[0] = 'a';
1029     wszPath[1] = '\0';
1030     result = pSHGetPathFromIDListW(NULL, wszPath);
1031     ok(!result, "Expected failure\n");
1032     ok(!wszPath[0], "Expected empty string\n");
1033
1034     /* Calling SHGetPathFromIDListW with an empty pidl should return the desktop folder's path. */
1035     result = pSHGetSpecialFolderPathW(NULL, wszDesktop, CSIDL_DESKTOP, FALSE);
1036     ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOP) failed! Last error: %u\n", GetLastError());
1037     if (!result) return;
1038
1039     /* Check if we are on Win9x */
1040     SetLastError(0xdeadbeef);
1041     lstrcmpiW(wszDesktop, wszDesktop);
1042     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1043     {
1044         win_skip("Most W-calls are not implemented\n");
1045         return;
1046     }
1047
1048     result = pSHGetPathFromIDListW(pidlEmpty, wszPath);
1049     ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1050     if (!result) return;
1051     ok(!lstrcmpiW(wszDesktop, wszPath), "SHGetPathFromIDListW didn't return desktop path for empty pidl!\n");
1052
1053     /* MyComputer does not map to a filesystem path. SHGetPathFromIDListW should fail. */
1054     hr = SHGetDesktopFolder(&psfDesktop);
1055     ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1056     if (hr != S_OK) return;
1057
1058     hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1059     ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1060     if (hr != S_OK) {
1061         IShellFolder_Release(psfDesktop);
1062         return;
1063     }
1064
1065     SetLastError(0xdeadbeef);
1066     wszPath[0] = 'a';
1067     wszPath[1] = '\0';
1068     result = pSHGetPathFromIDListW(pidlMyComputer, wszPath);
1069     ok (!result, "SHGetPathFromIDListW succeeded where it shouldn't!\n");
1070     ok (GetLastError()==0xdeadbeef ||
1071         GetLastError()==ERROR_SUCCESS, /* Vista and higher */
1072         "Unexpected last error from SHGetPathFromIDListW: %u\n", GetLastError());
1073     ok (!wszPath[0], "Expected empty path\n");
1074     if (result) {
1075         IShellFolder_Release(psfDesktop);
1076         return;
1077     }
1078
1079     IMalloc_Free(ppM, pidlMyComputer);
1080
1081     result = pSHGetSpecialFolderPathW(NULL, wszFileName, CSIDL_DESKTOPDIRECTORY, FALSE);
1082     ok(result, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1083     if (!result) {
1084         IShellFolder_Release(psfDesktop);
1085         return;
1086     }
1087     myPathAddBackslashW(wszFileName);
1088     lstrcatW(wszFileName, wszTestFile);
1089     hTestFile = CreateFileW(wszFileName, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
1090     ok(hTestFile != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: %u\n", GetLastError());
1091     if (hTestFile == INVALID_HANDLE_VALUE) {
1092         IShellFolder_Release(psfDesktop);
1093         return;
1094     }
1095     CloseHandle(hTestFile);
1096
1097     hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
1098     ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse filename hr = %08x\n", hr);
1099     if (hr != S_OK) {
1100         IShellFolder_Release(psfDesktop);
1101         DeleteFileW(wszFileName);
1102         IMalloc_Free(ppM, pidlTestFile);
1103         return;
1104     }
1105
1106     /* This test is to show that the Desktop shellfolder prepends the CSIDL_DESKTOPDIRECTORY
1107      * path for files placed on the desktop, if called with SHGDN_FORPARSING. */
1108     hr = IShellFolder_GetDisplayNameOf(psfDesktop, pidlTestFile, SHGDN_FORPARSING, &strret);
1109     ok (hr == S_OK, "Desktop's GetDisplayNamfOf failed! hr = %08x\n", hr);
1110     IShellFolder_Release(psfDesktop);
1111     DeleteFileW(wszFileName);
1112     if (hr != S_OK) {
1113         IMalloc_Free(ppM, pidlTestFile);
1114         return;
1115     }
1116     if (pStrRetToBufW)
1117     {
1118         pStrRetToBufW(&strret, pidlTestFile, wszPath, MAX_PATH);
1119         ok(0 == lstrcmpW(wszFileName, wszPath), 
1120            "Desktop->GetDisplayNameOf(pidlTestFile, SHGDN_FORPARSING) "
1121            "returned incorrect path for file placed on desktop\n");
1122     }
1123
1124     result = pSHGetPathFromIDListW(pidlTestFile, wszPath);
1125     ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1126     IMalloc_Free(ppM, pidlTestFile);
1127     if (!result) return;
1128     ok(0 == lstrcmpW(wszFileName, wszPath), "SHGetPathFromIDListW returned incorrect path for file placed on desktop\n");
1129
1130
1131     /* Test if we can get the path from the start menu "program files" PIDL. */
1132     hr = pSHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidlPrograms);
1133     ok(hr == S_OK, "SHGetFolderLocation failed: 0x%08x\n", hr);
1134
1135     SetLastError(0xdeadbeef);
1136     result = pSHGetPathFromIDListW(pidlPrograms, wszPath);
1137         IMalloc_Free(ppM, pidlPrograms);
1138     ok(result, "SHGetPathFromIDListW failed\n");
1139 }
1140
1141 static void test_EnumObjects_and_CompareIDs(void)
1142 {
1143     ITEMIDLIST *newPIDL;
1144     IShellFolder *IDesktopFolder, *testIShellFolder;
1145     char  cCurrDirA [MAX_PATH] = {0};
1146     static const CHAR cTestDirA[] = "\\testdir";
1147     WCHAR cTestDirW[MAX_PATH];
1148     int len;
1149     HRESULT hr;
1150
1151     GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1152     len = lstrlenA(cCurrDirA);
1153
1154     if(len == 0) {
1155         win_skip("GetCurrentDirectoryA returned empty string. Skipping test_EnumObjects_and_CompareIDs\n");
1156         return;
1157     }
1158     if(cCurrDirA[len-1] == '\\')
1159         cCurrDirA[len-1] = 0;
1160
1161     lstrcatA(cCurrDirA, cTestDirA);
1162     MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cTestDirW, MAX_PATH);
1163
1164     hr = SHGetDesktopFolder(&IDesktopFolder);
1165     ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1166
1167     CreateFilesFolders();
1168
1169     hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1170     ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1171
1172     hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1173     ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1174
1175     test_EnumObjects(testIShellFolder);
1176
1177     IShellFolder_Release(testIShellFolder);
1178
1179     Cleanup();
1180
1181     IMalloc_Free(ppM, newPIDL);
1182
1183     IShellFolder_Release(IDesktopFolder);
1184 }
1185
1186 /* A simple implementation of an IPropertyBag, which returns fixed values for
1187  * 'Target' and 'Attributes' properties.
1188  */
1189 static HRESULT WINAPI InitPropertyBag_IPropertyBag_QueryInterface(IPropertyBag *iface, REFIID riid,
1190     void **ppvObject) 
1191 {
1192     if (!ppvObject)
1193         return E_INVALIDARG;
1194
1195     if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPropertyBag, riid)) {
1196         *ppvObject = iface;
1197     } else {
1198         ok (FALSE, "InitPropertyBag asked for unknown interface!\n");
1199         return E_NOINTERFACE;
1200     }
1201
1202     IPropertyBag_AddRef(iface);
1203     return S_OK;
1204 }
1205
1206 static ULONG WINAPI InitPropertyBag_IPropertyBag_AddRef(IPropertyBag *iface) {
1207     return 2;
1208 }
1209
1210 static ULONG WINAPI InitPropertyBag_IPropertyBag_Release(IPropertyBag *iface) {
1211     return 1;
1212 }
1213
1214 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Read(IPropertyBag *iface, LPCOLESTR pszPropName,
1215     VARIANT *pVar, IErrorLog *pErrorLog)
1216 {
1217     static const WCHAR wszTargetSpecialFolder[] = {
1218         'T','a','r','g','e','t','S','p','e','c','i','a','l','F','o','l','d','e','r',0 };
1219     static const WCHAR wszTarget[] = {
1220         'T','a','r','g','e','t',0 };
1221     static const WCHAR wszAttributes[] = {
1222         'A','t','t','r','i','b','u','t','e','s',0 };
1223     static const WCHAR wszResolveLinkFlags[] = {
1224         'R','e','s','o','l','v','e','L','i','n','k','F','l','a','g','s',0 };
1225     static const WCHAR wszTargetKnownFolder[] = {
1226         'T','a','r','g','e','t','K','n','o','w','n','F','o','l','d','e','r',0 };
1227     static const WCHAR wszCLSID[] = {
1228         'C','L','S','I','D',0 };
1229        
1230     if (!lstrcmpW(pszPropName, wszTargetSpecialFolder)) {
1231         ok(V_VT(pVar) == VT_I4 ||
1232            broken(V_VT(pVar) == VT_BSTR),   /* Win2k */
1233            "Wrong variant type for 'TargetSpecialFolder' property!\n");
1234         return E_INVALIDARG;
1235     }
1236     
1237     if (!lstrcmpW(pszPropName, wszResolveLinkFlags)) 
1238     {
1239         ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'ResolveLinkFlags' property!\n");
1240         return E_INVALIDARG;
1241     }
1242
1243     if (!lstrcmpW(pszPropName, wszTarget)) {
1244         WCHAR wszPath[MAX_PATH];
1245         BOOL result;
1246         
1247         ok(V_VT(pVar) == VT_BSTR ||
1248            broken(V_VT(pVar) == VT_EMPTY),  /* Win2k */
1249            "Wrong variant type for 'Target' property!\n");
1250         if (V_VT(pVar) != VT_BSTR) return E_INVALIDARG;
1251
1252         result = pSHGetSpecialFolderPathW(NULL, wszPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1253         ok(result, "SHGetSpecialFolderPathW(DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1254         if (!result) return E_INVALIDARG;
1255
1256         V_BSTR(pVar) = SysAllocString(wszPath);
1257         return S_OK;
1258     }
1259
1260     if (!lstrcmpW(pszPropName, wszAttributes)) {
1261         ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'Attributes' property!\n");
1262         if (V_VT(pVar) != VT_UI4) return E_INVALIDARG;
1263         V_UI4(pVar) = SFGAO_FOLDER|SFGAO_HASSUBFOLDER|SFGAO_FILESYSANCESTOR|
1264                       SFGAO_CANRENAME|SFGAO_FILESYSTEM;
1265         return S_OK;
1266     }
1267
1268     if (!lstrcmpW(pszPropName, wszTargetKnownFolder)) {
1269         ok(V_VT(pVar) == VT_BSTR, "Wrong variant type for 'TargetKnownFolder' property!\n");
1270         /* TODO */
1271         return E_INVALIDARG;
1272     }
1273
1274     if (!lstrcmpW(pszPropName, wszCLSID)) {
1275         ok(V_VT(pVar) == VT_EMPTY, "Wrong variant type for 'CLSID' property!\n");
1276         /* TODO */
1277         return E_INVALIDARG;
1278     }
1279
1280     ok(FALSE, "PropertyBag was asked for unknown property %s (vt=%d)!\n", wine_dbgstr_w(pszPropName), V_VT(pVar));
1281     return E_INVALIDARG;
1282 }
1283
1284 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Write(IPropertyBag *iface, LPCOLESTR pszPropName,
1285     VARIANT *pVar)
1286 {
1287     ok(FALSE, "Unexpected call to IPropertyBag_Write\n");
1288     return E_NOTIMPL;
1289 }
1290     
1291 static const IPropertyBagVtbl InitPropertyBag_IPropertyBagVtbl = {
1292     InitPropertyBag_IPropertyBag_QueryInterface,
1293     InitPropertyBag_IPropertyBag_AddRef,
1294     InitPropertyBag_IPropertyBag_Release,
1295     InitPropertyBag_IPropertyBag_Read,
1296     InitPropertyBag_IPropertyBag_Write
1297 };
1298
1299 static struct IPropertyBag InitPropertyBag = {
1300     &InitPropertyBag_IPropertyBagVtbl
1301 };
1302
1303 static void test_FolderShortcut(void) {
1304     IPersistPropertyBag *pPersistPropertyBag;
1305     IShellFolder *pShellFolder, *pDesktopFolder;
1306     IPersistFolder3 *pPersistFolder3;
1307     HRESULT hr;
1308     STRRET strret;
1309     WCHAR wszDesktopPath[MAX_PATH], wszBuffer[MAX_PATH];
1310     BOOL result;
1311     CLSID clsid;
1312     LPITEMIDLIST pidlCurrentFolder, pidlWineTestFolder, pidlSubFolder;
1313     HKEY hShellExtKey;
1314     WCHAR wszWineTestFolder[] = {
1315         ':',':','{','9','B','3','5','2','E','B','F','-','2','7','6','5','-','4','5','C','1','-',
1316         'B','4','C','6','-','8','5','C','C','7','F','7','A','B','C','6','4','}',0 };
1317     WCHAR wszShellExtKey[] = { 'S','o','f','t','w','a','r','e','\\',
1318         'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
1319         'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1320         'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
1321         'N','a','m','e','S','p','a','c','e','\\',
1322         '{','9','b','3','5','2','e','b','f','-','2','7','6','5','-','4','5','c','1','-',
1323         'b','4','c','6','-','8','5','c','c','7','f','7','a','b','c','6','4','}',0 };
1324     
1325     WCHAR wszSomeSubFolder[] = { 'S','u','b','F','o','l','d','e','r', 0};
1326     static const GUID CLSID_UnixDosFolder = 
1327         {0x9d20aae8, 0x0625, 0x44b0, {0x9c, 0xa7, 0x71, 0x88, 0x9c, 0x22, 0x54, 0xd9}};
1328
1329     if (!pSHGetSpecialFolderPathW || !pStrRetToBufW) {
1330         win_skip("SHGetSpecialFolderPathW and/or StrRetToBufW are not available\n");
1331         return;
1332     }
1333
1334     if (!pSHGetFolderPathAndSubDirA)
1335     {
1336         win_skip("FolderShortcut test doesn't work on Win2k\n");
1337         return;
1338     }
1339
1340     /* These tests basically show, that CLSID_FolderShortcuts are initialized
1341      * via their IPersistPropertyBag interface. And that the target folder
1342      * is taken from the IPropertyBag's 'Target' property.
1343      */
1344     hr = CoCreateInstance(&CLSID_FolderShortcut, NULL, CLSCTX_INPROC_SERVER, 
1345                           &IID_IPersistPropertyBag, (LPVOID*)&pPersistPropertyBag);
1346     if (hr == REGDB_E_CLASSNOTREG) {
1347         win_skip("CLSID_FolderShortcut is not implemented\n");
1348         return;
1349     }
1350     ok (hr == S_OK, "CoCreateInstance failed! hr = 0x%08x\n", hr);
1351     if (hr != S_OK) return;
1352
1353     hr = IPersistPropertyBag_Load(pPersistPropertyBag, &InitPropertyBag, NULL);
1354     ok(hr == S_OK, "IPersistPropertyBag_Load failed! hr = %08x\n", hr);
1355     if (hr != S_OK) {
1356         IPersistPropertyBag_Release(pPersistPropertyBag);
1357         return;
1358     }
1359
1360     hr = IPersistPropertyBag_QueryInterface(pPersistPropertyBag, &IID_IShellFolder, 
1361                                             (LPVOID*)&pShellFolder);
1362     IPersistPropertyBag_Release(pPersistPropertyBag);
1363     ok(hr == S_OK, "IPersistPropertyBag_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1364     if (hr != S_OK) return;
1365
1366     hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1367     ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1368     if (hr != S_OK) {
1369         IShellFolder_Release(pShellFolder);
1370         return;
1371     }
1372
1373     result = pSHGetSpecialFolderPathW(NULL, wszDesktopPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1374     ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1375     if (!result) return;
1376
1377     pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1378     ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1379
1380     hr = IShellFolder_QueryInterface(pShellFolder, &IID_IPersistFolder3, (LPVOID*)&pPersistFolder3);
1381     IShellFolder_Release(pShellFolder);
1382     ok(hr == S_OK, "IShellFolder_QueryInterface(IID_IPersistFolder3 failed! hr = 0x%08x\n", hr);
1383     if (hr != S_OK) return;
1384
1385     hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1386     ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1387     ok(IsEqualCLSID(&clsid, &CLSID_FolderShortcut), "Unexpected CLSID!\n");
1388
1389     hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1390     todo_wine ok(hr == S_FALSE, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1391     ok(!pidlCurrentFolder, "IPersistFolder3_GetCurFolder should return a NULL pidl!\n");
1392                     
1393     /* For FolderShortcut objects, the Initialize method initialized the folder's position in the
1394      * shell namespace. The target folder, read from the property bag above, remains untouched. 
1395      * The following tests show this: The itemidlist for some imaginary shellfolder object
1396      * is created and the FolderShortcut is initialized with it. GetCurFolder now returns this
1397      * itemidlist, but GetDisplayNameOf still returns the path from above.
1398      */
1399     hr = SHGetDesktopFolder(&pDesktopFolder);
1400     ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1401     if (hr != S_OK) return;
1402
1403     /* Temporarily register WineTestFolder as a shell namespace extension at the Desktop. 
1404      * Otherwise ParseDisplayName fails on WinXP with E_INVALIDARG */
1405     RegCreateKeyW(HKEY_CURRENT_USER, wszShellExtKey, &hShellExtKey);
1406     RegCloseKey(hShellExtKey);
1407     hr = IShellFolder_ParseDisplayName(pDesktopFolder, NULL, NULL, wszWineTestFolder, NULL,
1408                                        &pidlWineTestFolder, NULL);
1409     RegDeleteKeyW(HKEY_CURRENT_USER, wszShellExtKey);
1410     IShellFolder_Release(pDesktopFolder);
1411     ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1412     if (hr != S_OK) return;
1413
1414     hr = IPersistFolder3_Initialize(pPersistFolder3, pidlWineTestFolder);
1415     ok (hr == S_OK, "IPersistFolder3::Initialize failed! hr = %08x\n", hr);
1416     if (hr != S_OK) {
1417         IPersistFolder3_Release(pPersistFolder3);
1418         pILFree(pidlWineTestFolder);
1419         return;
1420     }
1421
1422     hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1423     ok(hr == S_OK, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1424     ok(pILIsEqual(pidlCurrentFolder, pidlWineTestFolder),
1425         "IPersistFolder3_GetCurFolder should return pidlWineTestFolder!\n");
1426     pILFree(pidlCurrentFolder);
1427     pILFree(pidlWineTestFolder);
1428
1429     hr = IPersistFolder3_QueryInterface(pPersistFolder3, &IID_IShellFolder, (LPVOID*)&pShellFolder);
1430     IPersistFolder3_Release(pPersistFolder3);
1431     ok(hr == S_OK, "IPersistFolder3_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1432     if (hr != S_OK) return;
1433
1434     hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1435     ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1436     if (hr != S_OK) {
1437         IShellFolder_Release(pShellFolder);
1438         return;
1439     }
1440
1441     pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1442     ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1443
1444     /* Next few lines are meant to show that children of FolderShortcuts are not FolderShortcuts,
1445      * but ShellFSFolders. */
1446     myPathAddBackslashW(wszDesktopPath);
1447     lstrcatW(wszDesktopPath, wszSomeSubFolder);
1448     if (!CreateDirectoryW(wszDesktopPath, NULL)) {
1449         IShellFolder_Release(pShellFolder);
1450         return;
1451     }
1452     
1453     hr = IShellFolder_ParseDisplayName(pShellFolder, NULL, NULL, wszSomeSubFolder, NULL, 
1454                                        &pidlSubFolder, NULL);
1455     RemoveDirectoryW(wszDesktopPath);
1456     ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1457     if (hr != S_OK) {
1458         IShellFolder_Release(pShellFolder);
1459         return;
1460     }
1461
1462     hr = IShellFolder_BindToObject(pShellFolder, pidlSubFolder, NULL, &IID_IPersistFolder3,
1463                                    (LPVOID*)&pPersistFolder3);
1464     IShellFolder_Release(pShellFolder);
1465     pILFree(pidlSubFolder);
1466     ok (hr == S_OK, "IShellFolder::BindToObject failed! hr = %08x\n", hr);
1467     if (hr != S_OK)
1468         return;
1469
1470     /* On windows, we expect CLSID_ShellFSFolder. On wine we relax this constraint
1471      * a little bit and also allow CLSID_UnixDosFolder. */
1472     hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1473     ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1474     ok(IsEqualCLSID(&clsid, &CLSID_ShellFSFolder) || IsEqualCLSID(&clsid, &CLSID_UnixDosFolder),
1475         "IPersistFolder3::GetClassID returned unexpected CLSID!\n");
1476
1477     IPersistFolder3_Release(pPersistFolder3);
1478 }
1479
1480 #include "pshpack1.h"
1481 struct FileStructA {
1482     BYTE  type;
1483     BYTE  dummy;
1484     DWORD dwFileSize;
1485     WORD  uFileDate;    /* In our current implementation this is */
1486     WORD  uFileTime;    /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastWriteTime) */
1487     WORD  uFileAttribs;
1488     CHAR  szName[1];
1489 };
1490
1491 struct FileStructW {
1492     WORD  cbLen;        /* Length of this element. */
1493     BYTE  abFooBar1[6]; /* Beyond any recognition. */
1494     WORD  uDate;        /* FileTimeToDosDate(WIN32_FIND_DATA->ftCreationTime)? */
1495     WORD  uTime;        /* (this is currently speculation) */
1496     WORD  uDate2;       /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastAccessTime)? */
1497     WORD  uTime2;       /* (this is currently speculation) */
1498     BYTE  abFooBar2[4]; /* Beyond any recognition. */
1499     WCHAR wszName[1];   /* The long filename in unicode. */
1500     /* Just for documentation: Right after the unicode string: */
1501     WORD  cbOffset;     /* FileStructW's offset from the beginning of the SHITMEID. 
1502                          * SHITEMID->cb == uOffset + cbLen */
1503 };
1504 #include "poppack.h"
1505
1506 static void test_ITEMIDLIST_format(void) {
1507     WCHAR wszPersonal[MAX_PATH];
1508     LPSHELLFOLDER psfDesktop, psfPersonal;
1509     LPITEMIDLIST pidlPersonal, pidlFile;
1510     HANDLE hFile;
1511     HRESULT hr;
1512     BOOL bResult;
1513     WCHAR wszFile[3][17] = { { 'e','v','e','n','_',0 }, { 'o','d','d','_',0 },
1514         { 'l','o','n','g','e','r','_','t','h','a','n','.','8','_','3',0 } };
1515     int i;
1516
1517     if (!pSHGetSpecialFolderPathW) return;
1518
1519     bResult = pSHGetSpecialFolderPathW(NULL, wszPersonal, CSIDL_PERSONAL, FALSE);
1520     ok(bResult, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1521     if (!bResult) return;
1522
1523     SetLastError(0xdeadbeef);
1524     bResult = SetCurrentDirectoryW(wszPersonal);
1525     if (!bResult && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
1526         win_skip("Most W-calls are not implemented\n");
1527         return;
1528     }
1529     ok(bResult, "SetCurrentDirectory failed! Last error: %u\n", GetLastError());
1530     if (!bResult) return;
1531
1532     hr = SHGetDesktopFolder(&psfDesktop);
1533     ok(hr == S_OK, "SHGetDesktopFolder failed! hr: %08x\n", hr);
1534     if (hr != S_OK) return;
1535
1536     hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszPersonal, NULL, &pidlPersonal, NULL);
1537     ok(hr == S_OK, "psfDesktop->ParseDisplayName failed! hr = %08x\n", hr);
1538     if (hr != S_OK) {
1539         IShellFolder_Release(psfDesktop);
1540         return;
1541     }
1542
1543     hr = IShellFolder_BindToObject(psfDesktop, pidlPersonal, NULL, &IID_IShellFolder,
1544         (LPVOID*)&psfPersonal);
1545     IShellFolder_Release(psfDesktop);
1546     pILFree(pidlPersonal);
1547     ok(hr == S_OK, "psfDesktop->BindToObject failed! hr = %08x\n", hr);
1548     if (hr != S_OK) return;
1549
1550     for (i=0; i<3; i++) {
1551         CHAR szFile[MAX_PATH];
1552         struct FileStructA *pFileStructA;
1553         WORD cbOffset;
1554
1555         WideCharToMultiByte(CP_ACP, 0, wszFile[i], -1, szFile, MAX_PATH, NULL, NULL);
1556
1557         hFile = CreateFileW(wszFile[i], GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_FLAG_WRITE_THROUGH, NULL);
1558         ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed! (%u)\n", GetLastError());
1559         if (hFile == INVALID_HANDLE_VALUE) {
1560             IShellFolder_Release(psfPersonal);
1561             return;
1562         }
1563         CloseHandle(hFile);
1564
1565         hr = IShellFolder_ParseDisplayName(psfPersonal, NULL, NULL, wszFile[i], NULL, &pidlFile, NULL);
1566         DeleteFileW(wszFile[i]);
1567         ok(hr == S_OK, "psfPersonal->ParseDisplayName failed! hr: %08x\n", hr);
1568         if (hr != S_OK) {
1569             IShellFolder_Release(psfPersonal);
1570             return;
1571         }
1572
1573         pFileStructA = (struct FileStructA *)pidlFile->mkid.abID;
1574         ok(pFileStructA->type == 0x32, "PIDLTYPE should be 0x32!\n");
1575         ok(pFileStructA->dummy == 0x00, "Dummy Byte should be 0x00!\n");
1576         ok(pFileStructA->dwFileSize == 0, "Filesize should be zero!\n");
1577
1578         if (i < 2) /* First two file names are already in valid 8.3 format */
1579             ok(!strcmp(szFile, (CHAR*)&pidlFile->mkid.abID[12]), "Wrong file name!\n");
1580         else
1581             /* WinXP stores a derived 8.3 dos name (LONGER~1.8_3) here. We probably
1582              * can't implement this correctly, since unix filesystems don't support
1583              * this nasty short/long filename stuff. So we'll probably stay with our
1584              * current habbit of storing the long filename here, which seems to work
1585              * just fine. */
1586             todo_wine
1587             ok(pidlFile->mkid.abID[18] == '~' ||
1588                broken(pidlFile->mkid.abID[34] == '~'),  /* Win2k */
1589                "Should be derived 8.3 name!\n");
1590
1591         if (i == 0) /* First file name has an even number of chars. No need for alignment. */
1592             ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] != '\0' ||
1593                broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1),    /* Win2k */
1594                 "Alignment byte, where there shouldn't be!\n");
1595
1596         if (i == 1) /* Second file name has an uneven number of chars => alignment byte */
1597             ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] == '\0',
1598                 "There should be an alignment byte, but isn't!\n");
1599
1600         /* The offset of the FileStructW member is stored as a WORD at the end of the pidl. */
1601         cbOffset = *(WORD*)(((LPBYTE)pidlFile)+pidlFile->mkid.cb-sizeof(WORD));
1602         ok ((cbOffset >= sizeof(struct FileStructA) &&
1603             cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW)) ||
1604             broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1) ||     /* Win2k on short names */
1605             broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 12 + 1),  /* Win2k on long names */
1606             "Wrong offset value (%d) stored at the end of the PIDL\n", cbOffset);
1607
1608         if (cbOffset >= sizeof(struct FileStructA) &&
1609             cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW))
1610         {
1611             struct FileStructW *pFileStructW = (struct FileStructW *)(((LPBYTE)pidlFile)+cbOffset);
1612
1613             ok(pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen,
1614                 "FileStructW's offset and length should add up to the PIDL's length!\n");
1615
1616             if (pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen) {
1617                 /* Since we just created the file, time of creation,
1618                  * time of last access and time of last write access just be the same.
1619                  * These tests seem to fail sometimes (on WinXP), if the test is run again shortly
1620                  * after the first run. I do remember something with NTFS keeping the creation time
1621                  * if a file is deleted and then created again within a couple of seconds or so.
1622                  * Might be the reason. */
1623                 ok (pFileStructA->uFileDate == pFileStructW->uDate &&
1624                     pFileStructA->uFileTime == pFileStructW->uTime,
1625                     "Last write time should match creation time!\n");
1626
1627                 /* On FAT filesystems the last access time is midnight
1628                    local time, so the values of uDate2 and uTime2 will
1629                    depend on the local timezone.  If the times are exactly
1630                    equal then the dates should be identical for both FAT
1631                    and NTFS as no timezone is more than 1 day away from UTC.
1632                 */
1633                 if (pFileStructA->uFileTime == pFileStructW->uTime2)
1634                 {
1635                     ok (pFileStructA->uFileDate == pFileStructW->uDate2,
1636                         "Last write date and time should match last access date and time!\n");
1637                 }
1638                 else
1639                 {
1640                     /* Filesystem may be FAT. Check date within 1 day
1641                        and seconds are zero. */
1642                     trace ("Filesystem may be FAT. Performing less strict atime test.\n");
1643                     ok ((pFileStructW->uTime2 & 0x1F) == 0,
1644                         "Last access time on FAT filesystems should have zero seconds.\n");
1645                     /* TODO: Perform check for date being within one day.*/
1646                 }
1647
1648                 ok (!lstrcmpW(wszFile[i], pFileStructW->wszName) ||
1649                     !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 22)) || /* Vista */
1650                     !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 26)), /* Win7 */
1651                     "The filename should be stored in unicode at this position!\n");
1652             }
1653         }
1654
1655         pILFree(pidlFile);
1656     }
1657
1658     IShellFolder_Release(psfPersonal);
1659 }
1660
1661 static void test_SHGetFolderPathAndSubDirA(void)
1662 {
1663     HRESULT ret;
1664     BOOL delret;
1665     DWORD dwret;
1666     int i;
1667     static char wine[] = "wine";
1668     static char winetemp[] = "wine\\temp";
1669     static char appdata[MAX_PATH];
1670     static char testpath[MAX_PATH];
1671     static char toolongpath[MAX_PATH+1];
1672
1673     if(!pSHGetFolderPathAndSubDirA)
1674     {
1675         win_skip("SHGetFolderPathAndSubDirA not present!\n");
1676         return;
1677     }
1678
1679     if(!pSHGetFolderPathA) {
1680         win_skip("SHGetFolderPathA not present!\n");
1681         return;
1682     }
1683     if(FAILED(pSHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdata)))
1684     {
1685         win_skip("SHGetFolderPathA failed for CSIDL_LOCAL_APPDATA!\n");
1686         return;
1687     }
1688
1689     sprintf(testpath, "%s\\%s", appdata, winetemp);
1690     delret = RemoveDirectoryA(testpath);
1691     if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) ) {
1692         win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1693         return;
1694     }
1695
1696     sprintf(testpath, "%s\\%s", appdata, wine);
1697     delret = RemoveDirectoryA(testpath);
1698     if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) && (ERROR_FILE_NOT_FOUND != GetLastError())) {
1699         win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1700         return;
1701     }
1702
1703     /* test invalid second parameter */
1704     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | 0xff, NULL, SHGFP_TYPE_CURRENT, wine, testpath);
1705     ok(E_INVALIDARG == ret, "expected E_INVALIDARG, got  %x\n", ret);
1706
1707     /* test fourth parameter */
1708     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, 2, winetemp, testpath);
1709     switch(ret) {
1710         case S_OK: /* winvista */
1711             ok(!strncmp(appdata, testpath, strlen(appdata)),
1712                 "expected %s to start with %s\n", testpath, appdata);
1713             ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1714                 "expected %s to end with %s\n", testpath, winetemp);
1715             break;
1716         case E_INVALIDARG: /* winxp, win2k3 */
1717             break;
1718         default:
1719             ok(0, "expected S_OK or E_INVALIDARG, got  %x\n", ret);
1720     }
1721
1722     /* test fifth parameter */
1723     testpath[0] = '\0';
1724     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, NULL, testpath);
1725     ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1726     ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1727
1728     testpath[0] = '\0';
1729     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "", testpath);
1730     ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1731     ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1732
1733     testpath[0] = '\0';
1734     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "\\", testpath);
1735     ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1736     ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1737
1738     for(i=0; i< MAX_PATH; i++)
1739         toolongpath[i] = '0' + i % 10;
1740     toolongpath[MAX_PATH] = '\0';
1741     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, toolongpath, testpath);
1742     ok(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) == ret,
1743         "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), ret);
1744
1745     testpath[0] = '\0';
1746     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wine, NULL);
1747     ok((S_OK == ret) || (E_INVALIDARG == ret), "expected S_OK or E_INVALIDARG, got %x\n", ret);
1748
1749     /* test a not existing path */
1750     testpath[0] = '\0';
1751     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
1752     ok(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == ret,
1753         "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), ret);
1754
1755     /* create a directory inside a not existing directory */
1756     testpath[0] = '\0';
1757     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_CREATE | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
1758     ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1759     ok(!strncmp(appdata, testpath, strlen(appdata)),
1760         "expected %s to start with %s\n", testpath, appdata);
1761     ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1762         "expected %s to end with %s\n", testpath, winetemp);
1763     dwret = GetFileAttributes(testpath);
1764     ok(FILE_ATTRIBUTE_DIRECTORY | dwret, "expected %x to contain FILE_ATTRIBUTE_DIRECTORY\n", dwret);
1765
1766     /* cleanup */
1767     sprintf(testpath, "%s\\%s", appdata, winetemp);
1768     RemoveDirectoryA(testpath);
1769     sprintf(testpath, "%s\\%s", appdata, wine);
1770     RemoveDirectoryA(testpath);
1771 }
1772
1773 static void test_LocalizedNames(void)
1774 {
1775     static char cCurrDirA[MAX_PATH];
1776     WCHAR cCurrDirW[MAX_PATH], tempbufW[25];
1777     IShellFolder *IDesktopFolder, *testIShellFolder;
1778     ITEMIDLIST *newPIDL;
1779     int len;
1780     HRESULT hr;
1781     static char resourcefile[MAX_PATH];
1782     DWORD res;
1783     HANDLE file;
1784     STRRET strret;
1785
1786     static const char desktopini_contents1[] =
1787         "[.ShellClassInfo]\r\n"
1788         "LocalizedResourceName=@";
1789     static const char desktopini_contents2[] =
1790         ",-1\r\n";
1791     static WCHAR foldernameW[] = {'t','e','s','t','f','o','l','d','e','r',0};
1792     static const WCHAR folderdisplayW[] = {'F','o','l','d','e','r',' ','N','a','m','e',' ','R','e','s','o','u','r','c','e',0};
1793
1794     /* create folder with desktop.ini and localized name in GetModuleFileNameA(NULL) */
1795     CreateDirectoryA(".\\testfolder", NULL);
1796
1797     SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")|FILE_ATTRIBUTE_SYSTEM);
1798
1799     GetModuleFileNameA(NULL, resourcefile, MAX_PATH);
1800
1801     file = CreateFileA(".\\testfolder\\desktop.ini", GENERIC_WRITE, 0, NULL,
1802                          CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1803     ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %i\n", GetLastError());
1804     ok(WriteFile(file, desktopini_contents1, strlen(desktopini_contents1), &res, NULL) &&
1805        WriteFile(file, resourcefile, strlen(resourcefile), &res, NULL) &&
1806        WriteFile(file, desktopini_contents2, strlen(desktopini_contents2), &res, NULL),
1807        "WriteFile failed %i\n", GetLastError());
1808     CloseHandle(file);
1809
1810     /* get IShellFolder for parent */
1811     GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1812     len = lstrlenA(cCurrDirA);
1813
1814     if (len == 0) {
1815         win_skip("GetCurrentDirectoryA returned empty string. Skipping test_LocalizedNames\n");
1816         goto cleanup;
1817     }
1818     if(cCurrDirA[len-1] == '\\')
1819         cCurrDirA[len-1] = 0;
1820
1821     MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1822
1823     hr = SHGetDesktopFolder(&IDesktopFolder);
1824     ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1825
1826     hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1827     ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1828
1829     hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1830     ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1831
1832     IMalloc_Free(ppM, newPIDL);
1833
1834     /* windows reads the display name from the resource */
1835     hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, foldernameW, NULL, &newPIDL, 0);
1836     ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1837
1838     hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER, &strret);
1839     ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1840
1841     if (hr == S_OK && pStrRetToBufW)
1842     {
1843         hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1844         ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1845         todo_wine
1846         ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
1847             broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
1848             "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1849     }
1850
1851     /* editing name is also read from the resource */
1852     hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FOREDITING, &strret);
1853     ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1854
1855     if (hr == S_OK && pStrRetToBufW)
1856     {
1857         hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1858         ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1859         todo_wine
1860         ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
1861             broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
1862             "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1863     }
1864
1865     /* parsing name is unchanged */
1866     hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FORPARSING, &strret);
1867     ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1868
1869     if (hr == S_OK && pStrRetToBufW)
1870     {
1871         hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1872         ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1873         ok (!lstrcmpiW(tempbufW, foldernameW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1874     }
1875
1876     IShellFolder_Release(IDesktopFolder);
1877     IShellFolder_Release(testIShellFolder);
1878
1879     IMalloc_Free(ppM, newPIDL);
1880
1881 cleanup:
1882     DeleteFileA(".\\testfolder\\desktop.ini");
1883     SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")&~FILE_ATTRIBUTE_SYSTEM);
1884     RemoveDirectoryA(".\\testfolder");
1885 }
1886
1887 static void test_SHCreateShellItem(void)
1888 {
1889     IShellItem *shellitem, *shellitem2;
1890     IPersistIDList *persistidl;
1891     LPITEMIDLIST pidl_cwd=NULL, pidl_testfile, pidl_abstestfile, pidl_test, pidl_desktop;
1892     HRESULT ret;
1893     char curdirA[MAX_PATH];
1894     WCHAR curdirW[MAX_PATH];
1895     WCHAR fnbufW[MAX_PATH];
1896     IShellFolder *desktopfolder=NULL, *currentfolder=NULL;
1897     static WCHAR testfileW[] = {'t','e','s','t','f','i','l','e',0};
1898
1899     GetCurrentDirectoryA(MAX_PATH, curdirA);
1900
1901     if (!pSHCreateShellItem)
1902     {
1903         win_skip("SHCreateShellItem isn't available\n");
1904         return;
1905     }
1906
1907     if (!lstrlenA(curdirA))
1908     {
1909         win_skip("GetCurrentDirectoryA returned empty string, skipping test_SHCreateShellItem\n");
1910         return;
1911     }
1912
1913     if(pSHGetSpecialFolderLocation)
1914     {
1915         ret = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
1916         ok(ret == S_OK, "Got 0x%08x\n", ret);
1917     }
1918     else
1919     {
1920         win_skip("pSHGetSpecialFolderLocation missing.\n");
1921         pidl_desktop = NULL;
1922     }
1923
1924     MultiByteToWideChar(CP_ACP, 0, curdirA, -1, curdirW, MAX_PATH);
1925
1926     ret = SHGetDesktopFolder(&desktopfolder);
1927     ok(SUCCEEDED(ret), "SHGetShellFolder returned %x\n", ret);
1928
1929     ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
1930     ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
1931
1932     ret = IShellFolder_BindToObject(desktopfolder, pidl_cwd, NULL, &IID_IShellFolder, (void**)&currentfolder);
1933     ok(SUCCEEDED(ret), "BindToObject returned %x\n", ret);
1934
1935     CreateTestFile(".\\testfile");
1936
1937     ret = IShellFolder_ParseDisplayName(currentfolder, NULL, NULL, testfileW, NULL, &pidl_testfile, NULL);
1938     ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
1939
1940     pidl_abstestfile = pILCombine(pidl_cwd, pidl_testfile);
1941
1942     ret = pSHCreateShellItem(NULL, NULL, NULL, &shellitem);
1943     ok(ret == E_INVALIDARG, "SHCreateShellItem returned %x\n", ret);
1944
1945     if (0) /* crashes on Windows XP */
1946     {
1947         pSHCreateShellItem(NULL, NULL, pidl_cwd, NULL);
1948         pSHCreateShellItem(pidl_cwd, NULL, NULL, &shellitem);
1949         pSHCreateShellItem(NULL, currentfolder, NULL, &shellitem);
1950         pSHCreateShellItem(pidl_cwd, currentfolder, NULL, &shellitem);
1951     }
1952
1953     ret = pSHCreateShellItem(NULL, NULL, pidl_cwd, &shellitem);
1954     ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
1955     if (SUCCEEDED(ret))
1956     {
1957         ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
1958         ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1959         if (SUCCEEDED(ret))
1960         {
1961             ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1962             ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1963             if (SUCCEEDED(ret))
1964             {
1965                 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
1966                 pILFree(pidl_test);
1967             }
1968             IPersistIDList_Release(persistidl);
1969         }
1970         IShellItem_Release(shellitem);
1971     }
1972
1973     ret = pSHCreateShellItem(pidl_cwd, NULL, pidl_testfile, &shellitem);
1974     ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
1975     if (SUCCEEDED(ret))
1976     {
1977         ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
1978         ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1979         if (SUCCEEDED(ret))
1980         {
1981             ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1982             ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1983             if (SUCCEEDED(ret))
1984             {
1985                 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
1986                 pILFree(pidl_test);
1987             }
1988             IPersistIDList_Release(persistidl);
1989         }
1990
1991         ret = IShellItem_GetParent(shellitem, &shellitem2);
1992         ok(SUCCEEDED(ret), "GetParent returned %x\n", ret);
1993         if (SUCCEEDED(ret))
1994         {
1995             ret = IShellItem_QueryInterface(shellitem2, &IID_IPersistIDList, (void**)&persistidl);
1996             ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1997             if (SUCCEEDED(ret))
1998             {
1999                 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2000                 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2001                 if (SUCCEEDED(ret))
2002                 {
2003                     ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2004                     pILFree(pidl_test);
2005                 }
2006                 IPersistIDList_Release(persistidl);
2007             }
2008             IShellItem_Release(shellitem2);
2009         }
2010
2011         IShellItem_Release(shellitem);
2012     }
2013
2014     ret = pSHCreateShellItem(NULL, currentfolder, pidl_testfile, &shellitem);
2015     ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2016     if (SUCCEEDED(ret))
2017     {
2018         ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2019         ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2020         if (SUCCEEDED(ret))
2021         {
2022             ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2023             ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2024             if (SUCCEEDED(ret))
2025             {
2026                 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2027                 pILFree(pidl_test);
2028             }
2029             IPersistIDList_Release(persistidl);
2030         }
2031         IShellItem_Release(shellitem);
2032     }
2033
2034     /* if a parent pidl and shellfolder are specified, the shellfolder is ignored */
2035     ret = pSHCreateShellItem(pidl_cwd, desktopfolder, pidl_testfile, &shellitem);
2036     ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2037     if (SUCCEEDED(ret))
2038     {
2039         ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2040         ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2041         if (SUCCEEDED(ret))
2042         {
2043             ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2044             ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2045             if (SUCCEEDED(ret))
2046             {
2047                 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2048                 pILFree(pidl_test);
2049             }
2050             IPersistIDList_Release(persistidl);
2051         }
2052         IShellItem_Release(shellitem);
2053     }
2054
2055     ret = pSHCreateShellItem(NULL, desktopfolder, pidl_testfile, &shellitem);
2056     ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2057     if (SUCCEEDED(ret))
2058     {
2059         ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2060         ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2061         if (SUCCEEDED(ret))
2062         {
2063             ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2064             ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2065             if (SUCCEEDED(ret))
2066             {
2067                 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2068                 pILFree(pidl_test);
2069             }
2070             IPersistIDList_Release(persistidl);
2071         }
2072
2073         IShellItem_Release(shellitem);
2074     }
2075
2076     ret = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
2077     ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2078     if (SUCCEEDED(ret))
2079     {
2080         ret = IShellItem_GetParent(shellitem, &shellitem2);
2081         ok(FAILED(ret), "Got 0x%08x\n", ret);
2082         if(SUCCEEDED(ret)) IShellItem_Release(shellitem2);
2083         IShellItem_Release(shellitem);
2084     }
2085
2086     /* SHCreateItemFromParsingName */
2087     if(pSHCreateItemFromParsingName)
2088     {
2089         if(0)
2090         {
2091             /* Crashes under windows 7 */
2092             ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, NULL);
2093         }
2094
2095         shellitem = (void*)0xdeadbeef;
2096         ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, (void**)&shellitem);
2097         ok(ret == E_INVALIDARG, "SHCreateItemFromParsingName returned %x\n", ret);
2098         ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2099
2100         ret = pSHCreateItemFromParsingName(testfileW, NULL, &IID_IShellItem, (void**)&shellitem);
2101         ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
2102            "SHCreateItemFromParsingName returned %x\n", ret);
2103         if(SUCCEEDED(ret)) IShellItem_Release(shellitem);
2104
2105         lstrcpyW(fnbufW, curdirW);
2106         myPathAddBackslashW(fnbufW);
2107         lstrcatW(fnbufW, testfileW);
2108
2109         ret = pSHCreateItemFromParsingName(fnbufW, NULL, &IID_IShellItem, (void**)&shellitem);
2110         ok(ret == S_OK, "SHCreateItemFromParsingName returned %x\n", ret);
2111         if(SUCCEEDED(ret))
2112         {
2113             LPWSTR tmp_fname;
2114             ret = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &tmp_fname);
2115             ok(ret == S_OK, "GetDisplayName returned %x\n", ret);
2116             if(SUCCEEDED(ret))
2117             {
2118                 ok(!lstrcmpW(fnbufW, tmp_fname), "strings not equal\n");
2119                 CoTaskMemFree(tmp_fname);
2120             }
2121             IShellItem_Release(shellitem);
2122         }
2123     }
2124     else
2125         win_skip("No SHCreateItemFromParsingName\n");
2126
2127
2128     /* SHCreateItemFromIDList */
2129     if(pSHCreateItemFromIDList)
2130     {
2131         if(0)
2132         {
2133             /* Crashes under win7 */
2134             ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, NULL);
2135         }
2136
2137         ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, (void**)&shellitem);
2138         ok(ret == E_INVALIDARG, "SHCreateItemFromIDList returned %x\n", ret);
2139
2140         ret = pSHCreateItemFromIDList(pidl_cwd, &IID_IShellItem, (void**)&shellitem);
2141         ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2142         if (SUCCEEDED(ret))
2143         {
2144             ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2145             ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2146             if (SUCCEEDED(ret))
2147             {
2148                 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2149                 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2150                 if (SUCCEEDED(ret))
2151                 {
2152                     ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2153                     pILFree(pidl_test);
2154                 }
2155                 IPersistIDList_Release(persistidl);
2156             }
2157             IShellItem_Release(shellitem);
2158         }
2159
2160         ret = pSHCreateItemFromIDList(pidl_testfile, &IID_IShellItem, (void**)&shellitem);
2161         ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2162         if (SUCCEEDED(ret))
2163         {
2164             ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2165             ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2166             if (SUCCEEDED(ret))
2167             {
2168                 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2169                 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2170                 if (SUCCEEDED(ret))
2171                 {
2172                     ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2173                     pILFree(pidl_test);
2174                 }
2175                 IPersistIDList_Release(persistidl);
2176             }
2177             IShellItem_Release(shellitem);
2178         }
2179     }
2180     else
2181         win_skip("No SHCreateItemFromIDList\n");
2182
2183     DeleteFileA(".\\testfile");
2184     pILFree(pidl_abstestfile);
2185     pILFree(pidl_testfile);
2186     pILFree(pidl_desktop);
2187     pILFree(pidl_cwd);
2188     IShellFolder_Release(currentfolder);
2189     IShellFolder_Release(desktopfolder);
2190 }
2191
2192 static void test_SHGetNameFromIDList(void)
2193 {
2194     IShellItem *shellitem;
2195     LPITEMIDLIST pidl;
2196     LPWSTR name_string;
2197     HRESULT hres;
2198     UINT i;
2199     static const DWORD flags[] = {
2200         SIGDN_NORMALDISPLAY, SIGDN_PARENTRELATIVEPARSING,
2201         SIGDN_DESKTOPABSOLUTEPARSING,SIGDN_PARENTRELATIVEEDITING,
2202         SIGDN_DESKTOPABSOLUTEEDITING, /*SIGDN_FILESYSPATH, SIGDN_URL, */
2203         SIGDN_PARENTRELATIVEFORADDRESSBAR,SIGDN_PARENTRELATIVE, -1234};
2204
2205     if(!pSHGetNameFromIDList)
2206     {
2207         win_skip("SHGetNameFromIDList missing.\n");
2208         return;
2209     }
2210
2211     /* These should be available on any platform that passed the above test. */
2212     ok(pSHCreateShellItem != NULL, "SHCreateShellItem missing.\n");
2213     ok(pSHBindToParent != NULL, "SHBindToParent missing.\n");
2214     ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
2215     ok(pStrRetToBufW != NULL, "StrRetToBufW missing.\n");
2216
2217     if(0)
2218     {
2219         /* Crashes under win7 */
2220         hres = pSHGetNameFromIDList(NULL, 0, NULL);
2221     }
2222
2223     hres = pSHGetNameFromIDList(NULL, 0, &name_string);
2224     ok(hres == E_INVALIDARG, "Got 0x%08x\n", hres);
2225
2226     /* Test the desktop */
2227     hres = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
2228     ok(hres == S_OK, "Got 0x%08x\n", hres);
2229     hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2230     ok(hres == S_OK, "Got 0x%08x\n", hres);
2231     if(SUCCEEDED(hres))
2232     {
2233         WCHAR *nameSI, *nameSH;
2234         WCHAR buf[MAX_PATH];
2235         HRESULT hrSI, hrSH, hrSF;
2236         STRRET strret;
2237         IShellFolder *psf;
2238         BOOL res;
2239
2240         SHGetDesktopFolder(&psf);
2241         for(i = 0; flags[i] != -1234; i++)
2242         {
2243             hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2244             ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2245             hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2246             ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2247             hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2248             ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2249
2250             if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2251                 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2252
2253             if(SUCCEEDED(hrSF))
2254             {
2255                 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2256                 if(SUCCEEDED(hrSI))
2257                     ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2258                 if(SUCCEEDED(hrSF))
2259                     ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2260             }
2261             if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2262             if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2263         }
2264         IShellFolder_Release(psf);
2265
2266         if(pSHGetPathFromIDListW){
2267             hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2268             ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2269             res = pSHGetPathFromIDListW(pidl, buf);
2270             ok(res == TRUE, "Got %d\n", res);
2271             if(SUCCEEDED(hrSI) && res)
2272                 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2273             if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2274         }else
2275             win_skip("pSHGetPathFromIDListW not available\n");
2276
2277         hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2278         todo_wine ok(hres == S_OK, "Got 0x%08x\n", hres);
2279         if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2280
2281         IShellItem_Release(shellitem);
2282     }
2283     pILFree(pidl);
2284
2285     /* Test the control panel */
2286     hres = pSHGetSpecialFolderLocation(NULL, CSIDL_CONTROLS, &pidl);
2287     ok(hres == S_OK, "Got 0x%08x\n", hres);
2288     hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2289     ok(hres == S_OK, "Got 0x%08x\n", hres);
2290     if(SUCCEEDED(hres))
2291     {
2292         WCHAR *nameSI, *nameSH;
2293         WCHAR buf[MAX_PATH];
2294         HRESULT hrSI, hrSH, hrSF;
2295         STRRET strret;
2296         IShellFolder *psf;
2297         BOOL res;
2298
2299         SHGetDesktopFolder(&psf);
2300         for(i = 0; flags[i] != -1234; i++)
2301         {
2302             hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2303             ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2304             hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2305             ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2306             hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2307             ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2308
2309             if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2310                 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2311
2312             if(SUCCEEDED(hrSF))
2313             {
2314                 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2315                 if(SUCCEEDED(hrSI))
2316                     ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2317                 if(SUCCEEDED(hrSF))
2318                     ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2319             }
2320             if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2321             if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2322         }
2323         IShellFolder_Release(psf);
2324
2325         if(pSHGetPathFromIDListW){
2326             hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2327             ok(hrSI == E_INVALIDARG, "Got 0x%08x\n", hrSI);
2328             res = pSHGetPathFromIDListW(pidl, buf);
2329             ok(res == FALSE, "Got %d\n", res);
2330             if(SUCCEEDED(hrSI) && res)
2331                 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2332             if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2333         }else
2334             win_skip("pSHGetPathFromIDListW not available\n");
2335
2336         hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2337         todo_wine ok(hres == E_NOTIMPL /* Win7 */ || hres == S_OK /* Vista */,
2338                      "Got 0x%08x\n", hres);
2339         if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2340
2341         IShellItem_Release(shellitem);
2342     }
2343     pILFree(pidl);
2344 }
2345
2346 static void test_SHGetItemFromDataObject(void)
2347 {
2348     IShellFolder *psfdesktop;
2349     IShellItem *psi;
2350     IShellView *psv;
2351     HRESULT hres;
2352
2353     if(!pSHGetItemFromDataObject)
2354     {
2355         win_skip("No SHGetItemFromDataObject.\n");
2356         return;
2357     }
2358
2359     if(0)
2360     {
2361         /* Crashes under win7 */
2362         hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, NULL);
2363     }
2364
2365     hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, (void**)&psv);
2366     ok(hres == E_INVALIDARG, "got 0x%08x\n", hres);
2367
2368     SHGetDesktopFolder(&psfdesktop);
2369
2370     hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
2371     ok(hres == S_OK, "got 0x%08x\n", hres);
2372     if(SUCCEEDED(hres))
2373     {
2374         IEnumIDList *peidl;
2375         IDataObject *pdo;
2376         SHCONTF enum_flags;
2377
2378         enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
2379         hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
2380         ok(hres == S_OK, "got 0x%08x\n", hres);
2381         if(SUCCEEDED(hres))
2382         {
2383             LPITEMIDLIST apidl[5];
2384             UINT count = 0, i;
2385
2386             for(count = 0; count < 5; count++)
2387                 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
2388                     break;
2389
2390             if(count)
2391             {
2392                 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
2393                                                   &IID_IDataObject, NULL, (void**)&pdo);
2394                 ok(hres == S_OK, "got 0x%08x\n", hres);
2395                 if(SUCCEEDED(hres))
2396                 {
2397                     hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2398                     ok(hres == S_OK, "got 0x%08x\n", hres);
2399                     if(SUCCEEDED(hres)) IShellItem_Release(psi);
2400                     hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2401                     ok(hres == S_OK, "got 0x%08x\n", hres);
2402                     if(SUCCEEDED(hres)) IShellItem_Release(psi);
2403                     hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2404                     ok(hres == S_OK, "got 0x%08x\n", hres);
2405                     if(SUCCEEDED(hres)) IShellItem_Release(psi);
2406                     hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2407                     ok(hres == S_OK, "got 0x%08x\n", hres);
2408                     if(SUCCEEDED(hres)) IShellItem_Release(psi);
2409                     hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2410                     ok(hres == S_OK, "got 0x%08x\n", hres);
2411                     if(SUCCEEDED(hres)) IShellItem_Release(psi);
2412
2413                     IDataObject_Release(pdo);
2414                 }
2415             }
2416             else
2417                 skip("No file(s) found - skipping single-file test.\n");
2418
2419             if(count > 1)
2420             {
2421                 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
2422                                                   &IID_IDataObject, NULL, (void**)&pdo);
2423                 ok(hres == S_OK, "got 0x%08x\n", hres);
2424                 if(SUCCEEDED(hres))
2425                 {
2426                     hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2427                     ok(hres == S_OK, "got 0x%08x\n", hres);
2428                     if(SUCCEEDED(hres)) IShellItem_Release(psi);
2429                     hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2430                     ok(hres == S_OK, "got 0x%08x\n", hres);
2431                     if(SUCCEEDED(hres)) IShellItem_Release(psi);
2432                     hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2433                     ok(hres == S_OK, "got 0x%08x\n", hres);
2434                     if(SUCCEEDED(hres)) IShellItem_Release(psi);
2435                     hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2436                     ok(hres == S_OK, "got 0x%08x\n", hres);
2437                     if(SUCCEEDED(hres)) IShellItem_Release(psi);
2438                     hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2439                     ok(hres == E_FAIL, "got 0x%08x\n", hres);
2440                     if(SUCCEEDED(hres)) IShellItem_Release(psi);
2441                     IDataObject_Release(pdo);
2442                 }
2443             }
2444             else
2445                 skip("zero or one file found - skipping multi-file test.\n");
2446
2447             for(i = 0; i < count; i++)
2448                 pILFree(apidl[i]);
2449
2450             IEnumIDList_Release(peidl);
2451         }
2452
2453         IShellView_Release(psv);
2454     }
2455
2456     IShellFolder_Release(psfdesktop);
2457 }
2458
2459 static void test_ShellItemCompare(void)
2460 {
2461     IShellItem *psi[9]; /* a\a, a\b, a\c, b\a, .. */
2462     IShellItem *psi_a, *psi_b, *psi_c;
2463     IShellFolder *psf_desktop, *psf_current;
2464     LPITEMIDLIST pidl_cwd;
2465     WCHAR curdirW[MAX_PATH];
2466     BOOL failed;
2467     HRESULT hr;
2468     static const WCHAR filesW[][9] = {
2469         {'a','\\','a',0}, {'a','\\','b',0}, {'a','\\','c',0},
2470         {'b','\\','a',0}, {'b','\\','b',0}, {'b','\\','c',0},
2471         {'c','\\','a',0}, {'c','\\','b',0}, {'c','\\','c',0} };
2472     int order;
2473     UINT i;
2474
2475     if(!pSHCreateShellItem)
2476     {
2477         win_skip("SHCreateShellItem missing.\n");
2478         return;
2479     }
2480
2481     GetCurrentDirectoryW(MAX_PATH, curdirW);
2482     if(!lstrlenW(curdirW))
2483     {
2484         skip("Failed to get current directory, skipping.\n");
2485         return;
2486     }
2487
2488     CreateDirectoryA(".\\a", NULL);
2489     CreateDirectoryA(".\\b", NULL);
2490     CreateDirectoryA(".\\c", NULL);
2491     CreateTestFile(".\\a\\a");
2492     CreateTestFile(".\\a\\b");
2493     CreateTestFile(".\\a\\c");
2494     CreateTestFile(".\\b\\a");
2495     CreateTestFile(".\\b\\b");
2496     CreateTestFile(".\\b\\c");
2497     CreateTestFile(".\\c\\a");
2498     CreateTestFile(".\\c\\b");
2499     CreateTestFile(".\\c\\c");
2500
2501     SHGetDesktopFolder(&psf_desktop);
2502     hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2503     ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2504     hr = IShellFolder_BindToObject(psf_desktop, pidl_cwd, NULL, &IID_IShellFolder, (void**)&psf_current);
2505     ok(SUCCEEDED(hr), "BindToObject returned %x\n", hr);
2506     IShellFolder_Release(psf_desktop);
2507
2508     /* Generate ShellItems for the files */
2509     ZeroMemory(&psi, sizeof(IShellItem*)*9);
2510     failed = FALSE;
2511     for(i = 0; i < 9; i++)
2512     {
2513         LPITEMIDLIST pidl_testfile = NULL;
2514
2515         hr = IShellFolder_ParseDisplayName(psf_current, NULL, NULL, (LPWSTR)filesW[i],
2516                                            NULL, &pidl_testfile, NULL);
2517         ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2518         if(SUCCEEDED(hr))
2519         {
2520             hr = pSHCreateShellItem(NULL, NULL, pidl_testfile, &psi[i]);
2521             ok(hr == S_OK, "Got 0x%08x\n", hr);
2522             pILFree(pidl_testfile);
2523         }
2524         if(FAILED(hr)) failed = TRUE;
2525     }
2526     if(failed)
2527     {
2528         skip("Failed to create all shellitems.\n");
2529         goto cleanup;
2530     }
2531
2532     /* Generate ShellItems for the folders */
2533     psi_a = psi_b = psi_c = NULL;
2534     hr = IShellItem_GetParent(psi[0], &psi_a);
2535     ok(hr == S_OK, "Got 0x%08x\n", hr);
2536     if(FAILED(hr)) failed = TRUE;
2537     hr = IShellItem_GetParent(psi[3], &psi_b);
2538     ok(hr == S_OK, "Got 0x%08x\n", hr);
2539     if(FAILED(hr)) failed = TRUE;
2540     hr = IShellItem_GetParent(psi[6], &psi_c);
2541     ok(hr == S_OK, "Got 0x%08x\n", hr);
2542     if(FAILED(hr)) failed = TRUE;
2543
2544     if(failed)
2545     {
2546         skip("Failed to create shellitems.\n");
2547         goto cleanup;
2548     }
2549
2550     if(0)
2551     {
2552         /* Crashes on native (win7, winxp) */
2553         hr = IShellItem_Compare(psi_a, NULL, 0, NULL);
2554         hr = IShellItem_Compare(psi_a, psi_b, 0, NULL);
2555         hr = IShellItem_Compare(psi_a, NULL, 0, &order);
2556     }
2557
2558     /* Basics */
2559     for(i = 0; i < 9; i++)
2560     {
2561         hr = IShellItem_Compare(psi[i], psi[i], SICHINT_DISPLAY, &order);
2562         ok(hr == S_OK, "Got 0x%08x\n", hr);
2563         ok(order == 0, "Got order %d\n", order);
2564         hr = IShellItem_Compare(psi[i], psi[i], SICHINT_CANONICAL, &order);
2565         ok(hr == S_OK, "Got 0x%08x\n", hr);
2566         ok(order == 0, "Got order %d\n", order);
2567         hr = IShellItem_Compare(psi[i], psi[i], SICHINT_ALLFIELDS, &order);
2568         ok(hr == S_OK, "Got 0x%08x\n", hr);
2569         ok(order == 0, "Got order %d\n", order);
2570     }
2571
2572     /* Order */
2573     /* a\b:a\a , a\b:a\c, a\b:a\b */
2574     hr = IShellItem_Compare(psi[1], psi[0], SICHINT_DISPLAY, &order);
2575     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2576     ok(order == 1, "Got order %d\n", order);
2577     hr = IShellItem_Compare(psi[1], psi[2], SICHINT_DISPLAY, &order);
2578     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2579     ok(order == -1, "Got order %d\n", order);
2580     hr = IShellItem_Compare(psi[1], psi[1], SICHINT_DISPLAY, &order);
2581     ok(hr == S_OK, "Got 0x%08x\n", hr);
2582     ok(order == 0, "Got order %d\n", order);
2583
2584     /* b\b:a\b, b\b:c\b, b\b:c\b */
2585     hr = IShellItem_Compare(psi[4], psi[1], SICHINT_DISPLAY, &order);
2586     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2587     ok(order == 1, "Got order %d\n", order);
2588     hr = IShellItem_Compare(psi[4], psi[7], SICHINT_DISPLAY, &order);
2589     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2590     ok(order == -1, "Got order %d\n", order);
2591     hr = IShellItem_Compare(psi[4], psi[4], SICHINT_DISPLAY, &order);
2592     ok(hr == S_OK, "Got 0x%08x\n", hr);
2593     ok(order == 0, "Got order %d\n", order);
2594
2595     /* b:a\a, b:a\c, b:a\b */
2596     hr = IShellItem_Compare(psi_b, psi[0], SICHINT_DISPLAY, &order);
2597     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2598     todo_wine ok(order == 1, "Got order %d\n", order);
2599     hr = IShellItem_Compare(psi_b, psi[2], SICHINT_DISPLAY, &order);
2600     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2601     todo_wine ok(order == 1, "Got order %d\n", order);
2602     hr = IShellItem_Compare(psi_b, psi[1], SICHINT_DISPLAY, &order);
2603     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2604     todo_wine ok(order == 1, "Got order %d\n", order);
2605
2606     /* b:c\a, b:c\c, b:c\b */
2607     hr = IShellItem_Compare(psi_b, psi[6], SICHINT_DISPLAY, &order);
2608     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2609     ok(order == -1, "Got order %d\n", order);
2610     hr = IShellItem_Compare(psi_b, psi[8], SICHINT_DISPLAY, &order);
2611     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2612     ok(order == -1, "Got order %d\n", order);
2613     hr = IShellItem_Compare(psi_b, psi[7], SICHINT_DISPLAY, &order);
2614     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2615     ok(order == -1, "Got order %d\n", order);
2616
2617     /* a\b:a\a , a\b:a\c, a\b:a\b */
2618     hr = IShellItem_Compare(psi[1], psi[0], SICHINT_CANONICAL, &order);
2619     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2620     ok(order == 1, "Got order %d\n", order);
2621     hr = IShellItem_Compare(psi[1], psi[2], SICHINT_CANONICAL, &order);
2622     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2623     ok(order == -1, "Got order %d\n", order);
2624     hr = IShellItem_Compare(psi[1], psi[1], SICHINT_CANONICAL, &order);
2625     ok(hr == S_OK, "Got 0x%08x\n", hr);
2626     ok(order == 0, "Got order %d\n", order);
2627
2628     /* b\b:a\b, b\b:c\b, b\b:c\b */
2629     hr = IShellItem_Compare(psi[4], psi[1], SICHINT_CANONICAL, &order);
2630     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2631     ok(order == 1, "Got order %d\n", order);
2632     hr = IShellItem_Compare(psi[4], psi[7], SICHINT_CANONICAL, &order);
2633     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2634     ok(order == -1, "Got order %d\n", order);
2635     hr = IShellItem_Compare(psi[4], psi[4], SICHINT_CANONICAL, &order);
2636     ok(hr == S_OK, "Got 0x%08x\n", hr);
2637     ok(order == 0, "Got order %d\n", order);
2638
2639     /* b:a\a, b:a\c, b:a\b */
2640     hr = IShellItem_Compare(psi_b, psi[0], SICHINT_CANONICAL, &order);
2641     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2642     todo_wine ok(order == 1, "Got order %d\n", order);
2643     hr = IShellItem_Compare(psi_b, psi[2], SICHINT_CANONICAL, &order);
2644     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2645     todo_wine ok(order == 1, "Got order %d\n", order);
2646     hr = IShellItem_Compare(psi_b, psi[1], SICHINT_CANONICAL, &order);
2647     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2648     todo_wine ok(order == 1, "Got order %d\n", order);
2649
2650     /* b:c\a, b:c\c, b:c\b */
2651     hr = IShellItem_Compare(psi_b, psi[6], SICHINT_CANONICAL, &order);
2652     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2653     ok(order == -1, "Got order %d\n", order);
2654     hr = IShellItem_Compare(psi_b, psi[8], SICHINT_CANONICAL, &order);
2655     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2656     ok(order == -1, "Got order %d\n", order);
2657     hr = IShellItem_Compare(psi_b, psi[7], SICHINT_CANONICAL, &order);
2658     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2659     ok(order == -1, "Got order %d\n", order);
2660
2661 cleanup:
2662     IShellFolder_Release(psf_current);
2663
2664     DeleteFileA(".\\a\\a");
2665     DeleteFileA(".\\a\\b");
2666     DeleteFileA(".\\a\\c");
2667     DeleteFileA(".\\b\\a");
2668     DeleteFileA(".\\b\\b");
2669     DeleteFileA(".\\b\\c");
2670     DeleteFileA(".\\c\\a");
2671     DeleteFileA(".\\c\\b");
2672     DeleteFileA(".\\c\\c");
2673     RemoveDirectoryA(".\\a");
2674     RemoveDirectoryA(".\\b");
2675     RemoveDirectoryA(".\\c");
2676
2677     if(psi_a) IShellItem_Release(psi_a);
2678     if(psi_b) IShellItem_Release(psi_b);
2679     if(psi_c) IShellItem_Release(psi_c);
2680
2681     for(i = 0; i < 9; i++)
2682         if(psi[i]) IShellItem_Release(psi[i]);
2683 }
2684
2685 /**************************************************************/
2686 /* IUnknown implementation for counting QueryInterface calls. */
2687 typedef struct {
2688     const IUnknownVtbl *lpVtbl;
2689     struct if_count {
2690         REFIID id;
2691         LONG count;
2692     } *ifaces;
2693     LONG unknown;
2694 } IUnknownImpl;
2695
2696 static HRESULT WINAPI unk_fnQueryInterface(IUnknown *iunk, REFIID riid, void** punk)
2697 {
2698     IUnknownImpl *This = (IUnknownImpl*)iunk;
2699     UINT i, found;
2700     for(i = found = 0; This->ifaces[i].id != NULL; i++)
2701     {
2702         if(IsEqualIID(This->ifaces[i].id, riid))
2703         {
2704             This->ifaces[i].count++;
2705             found = 1;
2706             break;
2707         }
2708     }
2709     if(!found)
2710         This->unknown++;
2711     return E_NOINTERFACE;
2712 }
2713
2714 static ULONG WINAPI unk_fnAddRef(IUnknown *iunk)
2715 {
2716     return 2;
2717 }
2718
2719 static ULONG WINAPI unk_fnRelease(IUnknown *iunk)
2720 {
2721     return 1;
2722 }
2723
2724 const IUnknownVtbl vt_IUnknown = {
2725     unk_fnQueryInterface,
2726     unk_fnAddRef,
2727     unk_fnRelease
2728 };
2729
2730 static void test_SHGetIDListFromObject(void)
2731 {
2732     IUnknownImpl *punkimpl;
2733     IShellFolder *psfdesktop;
2734     IShellView *psv;
2735     LPITEMIDLIST pidl, pidl_desktop;
2736     HRESULT hres;
2737     UINT i;
2738     struct if_count ifaces[] =
2739         { {&IID_IPersistIDList, 0},
2740           {&IID_IPersistFolder2, 0},
2741           {&IID_IDataObject, 0},
2742           {&IID_IParentAndItem, 0},
2743           {&IID_IFolderView, 0},
2744           {NULL, 0} };
2745
2746     if(!pSHGetIDListFromObject)
2747     {
2748         win_skip("SHGetIDListFromObject missing.\n");
2749         return;
2750     }
2751
2752     ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
2753
2754     if(0)
2755     {
2756         /* Crashes native */
2757         pSHGetIDListFromObject(NULL, NULL);
2758         pSHGetIDListFromObject((void*)0xDEADBEEF, NULL);
2759     }
2760
2761     hres = pSHGetIDListFromObject(NULL, &pidl);
2762     ok(hres == E_NOINTERFACE, "Got %x\n", hres);
2763
2764     punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
2765     punkimpl->lpVtbl = &vt_IUnknown;
2766     punkimpl->ifaces = ifaces;
2767     punkimpl->unknown = 0;
2768
2769     hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
2770     ok(hres == E_NOINTERFACE, "Got %x\n", hres);
2771     ok(ifaces[0].count, "interface not requested.\n");
2772     ok(ifaces[1].count, "interface not requested.\n");
2773     ok(ifaces[2].count, "interface not requested.\n");
2774     todo_wine
2775         ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
2776            "interface not requested.\n");
2777     ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
2778        "interface not requested.\n");
2779
2780     ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
2781     HeapFree(GetProcessHeap(), 0, punkimpl);
2782
2783     pidl_desktop = NULL;
2784     pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
2785     ok(pidl_desktop != NULL, "Failed to get desktop pidl.\n");
2786
2787     SHGetDesktopFolder(&psfdesktop);
2788
2789     /* Test IShellItem */
2790     if(pSHCreateShellItem)
2791     {
2792         IShellItem *shellitem;
2793         hres = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
2794         ok(hres == S_OK, "got 0x%08x\n", hres);
2795         if(SUCCEEDED(hres))
2796         {
2797             hres = pSHGetIDListFromObject((IUnknown*)shellitem, &pidl);
2798             ok(hres == S_OK, "got 0x%08x\n", hres);
2799             if(SUCCEEDED(hres))
2800             {
2801                 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
2802                 pILFree(pidl);
2803             }
2804             IShellItem_Release(shellitem);
2805         }
2806     }
2807     else
2808         skip("no SHCreateShellItem.\n");
2809
2810     /* Test IShellFolder */
2811     hres = pSHGetIDListFromObject((IUnknown*)psfdesktop, &pidl);
2812     ok(hres == S_OK, "got 0x%08x\n", hres);
2813     if(SUCCEEDED(hres))
2814     {
2815         ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
2816         pILFree(pidl);
2817     }
2818
2819     hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
2820     ok(hres == S_OK, "got 0x%08x\n", hres);
2821     if(SUCCEEDED(hres))
2822     {
2823         IEnumIDList *peidl;
2824         IDataObject *pdo;
2825         SHCONTF enum_flags;
2826
2827         /* Test IFolderView */
2828         hres = pSHGetIDListFromObject((IUnknown*)psv, &pidl);
2829         ok(hres == S_OK, "got 0x%08x\n", hres);
2830         if(SUCCEEDED(hres))
2831         {
2832             ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
2833             pILFree(pidl);
2834         }
2835
2836         /* Test IDataObject */
2837         enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
2838         hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
2839         ok(hres == S_OK, "got 0x%08x\n", hres);
2840         if(SUCCEEDED(hres))
2841         {
2842             LPITEMIDLIST apidl[5];
2843             UINT count = 0;
2844             for(count = 0; count < 5; count++)
2845                 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
2846                     break;
2847
2848             if(count)
2849             {
2850                 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
2851                                                   &IID_IDataObject, NULL, (void**)&pdo);
2852                 ok(hres == S_OK, "got 0x%08x\n", hres);
2853                 if(SUCCEEDED(hres))
2854                 {
2855                     pidl = (void*)0xDEADBEEF;
2856                     hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
2857                     ok(hres == S_OK, "got 0x%08x\n", hres);
2858                     ok(pidl != NULL, "pidl is NULL.\n");
2859                     ok(ILIsEqual(pidl, apidl[0]), "pidl not equal.\n");
2860                     pILFree(pidl);
2861
2862                     IDataObject_Release(pdo);
2863                 }
2864             }
2865             else
2866                 skip("No files found - skipping single-file test.\n");
2867
2868             if(count > 1)
2869             {
2870                 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
2871                                                   &IID_IDataObject, NULL, (void**)&pdo);
2872                 ok(hres == S_OK, "got 0x%08x\n", hres);
2873                 if(SUCCEEDED(hres))
2874                 {
2875                     pidl = (void*)0xDEADBEEF;
2876                     hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
2877                     ok(hres == E_NOINTERFACE || hres == E_FAIL /*Vista*/,
2878                        "got 0x%08x\n", hres);
2879                     ok(pidl == NULL, "pidl is not NULL.\n");
2880
2881                     IDataObject_Release(pdo);
2882                 }
2883             }
2884             else
2885                 skip("zero or one file found - skipping multi-file test.\n");
2886
2887             for(i = 0; i < count; i++)
2888                 pILFree(apidl[i]);
2889
2890             IEnumIDList_Release(peidl);
2891         }
2892
2893         IShellView_Release(psv);
2894     }
2895
2896     IShellFolder_Release(psfdesktop);
2897     pILFree(pidl_desktop);
2898 }
2899
2900 static void test_SHGetItemFromObject(void)
2901 {
2902     IUnknownImpl *punkimpl;
2903     IShellFolder *psfdesktop;
2904     LPITEMIDLIST pidl;
2905     IShellItem *psi;
2906     IUnknown *punk;
2907     HRESULT hres;
2908     struct if_count ifaces[] =
2909         { {&IID_IPersistIDList, 0},
2910           {&IID_IPersistFolder2, 0},
2911           {&IID_IDataObject, 0},
2912           {&IID_IParentAndItem, 0},
2913           {&IID_IFolderView, 0},
2914           {NULL, 0} };
2915
2916     if(!pSHGetItemFromObject)
2917     {
2918         skip("No SHGetItemFromObject.\n");
2919         return;
2920     }
2921
2922     SHGetDesktopFolder(&psfdesktop);
2923
2924     if(0)
2925     {
2926         /* Crashes with Windows 7 */
2927         hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IUnknown, NULL);
2928         hres = pSHGetItemFromObject(NULL, &IID_IUnknown, NULL);
2929         hres = pSHGetItemFromObject((IUnknown*)psfdesktop, NULL, (void**)&punk);
2930     }
2931
2932     hres = pSHGetItemFromObject(NULL, &IID_IUnknown, (void**)&punk);
2933     ok(hres == E_NOINTERFACE, "Got 0x%08x\n", hres);
2934
2935     punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
2936     punkimpl->lpVtbl = &vt_IUnknown;
2937     punkimpl->ifaces = ifaces;
2938     punkimpl->unknown = 0;
2939
2940     /* The same as SHGetIDListFromObject */
2941     hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
2942     ok(hres == E_NOINTERFACE, "Got %x\n", hres);
2943     ok(ifaces[0].count, "interface not requested.\n");
2944     ok(ifaces[1].count, "interface not requested.\n");
2945     ok(ifaces[2].count, "interface not requested.\n");
2946     todo_wine
2947         ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
2948            "interface not requested.\n");
2949     ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
2950        "interface not requested.\n");
2951
2952     ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
2953     HeapFree(GetProcessHeap(), 0, punkimpl);
2954
2955     /* Test IShellItem */
2956     hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IShellItem, (void**)&psi);
2957     ok(hres == S_OK, "Got 0x%08x\n", hres);
2958     if(SUCCEEDED(hres))
2959     {
2960         IShellItem *psi2;
2961         hres = pSHGetItemFromObject((IUnknown*)psi, &IID_IShellItem, (void**)&psi2);
2962         ok(hres == S_OK, "Got 0x%08x\n", hres);
2963         if(SUCCEEDED(hres))
2964         {
2965             todo_wine
2966                 ok(psi == psi2, "Different instances (%p != %p).\n", psi, psi2);
2967             IShellItem_Release(psi2);
2968         }
2969         IShellItem_Release(psi);
2970     }
2971
2972     IShellFolder_Release(psfdesktop);
2973 }
2974
2975 static void test_SHCreateShellItemArray(void)
2976 {
2977     IShellFolder *pdesktopsf, *psf;
2978     IShellItemArray *psia;
2979     IEnumIDList *peidl;
2980     HRESULT hr;
2981     WCHAR cTestDirW[MAX_PATH];
2982     LPITEMIDLIST pidl_testdir, pidl;
2983     static const WCHAR testdirW[] = {'t','e','s','t','d','i','r',0};
2984
2985     if(!pSHCreateShellItemArray) {
2986         skip("No pSHCreateShellItemArray!\n");
2987         return;
2988     }
2989
2990     ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
2991
2992     if(0)
2993     {
2994         /* Crashes under native */
2995         pSHCreateShellItemArray(NULL, NULL, 0, NULL, NULL);
2996         pSHCreateShellItemArray(NULL, NULL, 1, NULL, NULL);
2997         pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, NULL);
2998         pSHCreateShellItemArray(pidl, NULL, 0, NULL, NULL);
2999     }
3000
3001     hr = pSHCreateShellItemArray(NULL, NULL, 0, NULL, &psia);
3002     ok(hr == E_POINTER, "got 0x%08x\n", hr);
3003
3004     SHGetDesktopFolder(&pdesktopsf);
3005     hr = pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, &psia);
3006     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3007
3008     hr = pSHCreateShellItemArray(NULL, pdesktopsf, 1, NULL, &psia);
3009     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3010
3011     pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
3012     hr = pSHCreateShellItemArray(pidl, NULL, 0, NULL, &psia);
3013     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3014     pILFree(pidl);
3015
3016     GetCurrentDirectoryW(MAX_PATH, cTestDirW);
3017     myPathAddBackslashW(cTestDirW);
3018     lstrcatW(cTestDirW, testdirW);
3019
3020     CreateFilesFolders();
3021
3022     hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, cTestDirW, NULL, &pidl_testdir, 0);
3023     ok(hr == S_OK, "got 0x%08x\n", hr);
3024     if(SUCCEEDED(hr))
3025     {
3026         hr = IShellFolder_BindToObject(pdesktopsf, pidl_testdir, NULL, (REFIID)&IID_IShellFolder,
3027                                        (void**)&psf);
3028         ok(hr == S_OK, "Got 0x%08x\n", hr);
3029     }
3030     IShellFolder_Release(pdesktopsf);
3031
3032     if(FAILED(hr))
3033     {
3034         skip("Failed to set up environment for SHCreateShellItemArray tests.\n");
3035         pILFree(pidl_testdir);
3036         Cleanup();
3037         return;
3038     }
3039
3040     hr = IShellFolder_EnumObjects(psf, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &peidl);
3041     ok(hr == S_OK, "Got %08x\n", hr);
3042     if(SUCCEEDED(hr))
3043     {
3044         LPITEMIDLIST apidl[5];
3045         UINT done, numitems, i;
3046
3047         for(done = 0; done < 5; done++)
3048             if(IEnumIDList_Next(peidl, 1, &apidl[done], NULL) != S_OK)
3049                 break;
3050         ok(done == 5, "Got %d pidls\n", done);
3051         IEnumIDList_Release(peidl);
3052
3053         /* Create a ShellItemArray */
3054         hr = pSHCreateShellItemArray(NULL, psf, done, (LPCITEMIDLIST*)apidl, &psia);
3055         ok(hr == S_OK, "Got 0x%08x\n", hr);
3056         if(SUCCEEDED(hr))
3057         {
3058             IShellItem *psi;
3059
3060             if(0)
3061             {
3062                 /* Crashes in Windows 7 */
3063                 hr = IShellItemArray_GetCount(psia, NULL);
3064             }
3065
3066             IShellItemArray_GetCount(psia, &numitems);
3067             ok(numitems == done, "Got %d, expected %d\n", numitems, done);
3068
3069             hr = IShellItemArray_GetItemAt(psia, numitems, &psi);
3070             ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3071
3072             /* Compare all the items */
3073             for(i = 0; i < numitems; i++)
3074             {
3075                 LPITEMIDLIST pidl_abs;
3076                 pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3077
3078                 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3079                 ok(hr == S_OK, "(%d) Failed with 0x%08x\n", i, hr);
3080                 if(SUCCEEDED(hr))
3081                 {
3082                     hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3083                     ok(hr == S_OK, "Got 0x%08x\n", hr);
3084                     if(SUCCEEDED(hr))
3085                     {
3086                         ok(ILIsEqual(pidl_abs, pidl), "Pidl not equal.\n");
3087                         pILFree(pidl);
3088                     }
3089                     IShellItem_Release(psi);
3090                 }
3091                 pILFree(pidl_abs);
3092             }
3093             for(i = 0; i < done; i++)
3094                 pILFree(apidl[i]);
3095             IShellItemArray_Release(psia);
3096         }
3097     }
3098
3099     /* SHCreateShellItemArrayFromShellItem */
3100     if(pSHCreateShellItemArrayFromShellItem)
3101     {
3102         IShellItem *psi;
3103
3104         if(0)
3105         {
3106             /* Crashes under Windows 7 */
3107             hr = pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, NULL);
3108             hr = pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, (void**)&psia);
3109             hr = pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, NULL);
3110         }
3111
3112         hr = pSHCreateItemFromIDList(pidl_testdir, &IID_IShellItem, (void**)&psi);
3113         ok(hr == S_OK, "Got 0x%08x\n", hr);
3114         if(SUCCEEDED(hr))
3115         {
3116             hr = pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, (void**)&psia);
3117             ok(hr == S_OK, "Got 0x%08x\n", hr);
3118             if(SUCCEEDED(hr))
3119             {
3120                 IShellItem *psi2;
3121                 UINT count;
3122                 hr = IShellItemArray_GetCount(psia, &count);
3123                 ok(hr == S_OK, "Got 0x%08x\n", hr);
3124                 ok(count == 1, "Got count %d\n", count);
3125                 hr = IShellItemArray_GetItemAt(psia, 0, &psi2);
3126                 ok(hr == S_OK, "Got 0x%08x\n", hr);
3127                 todo_wine
3128                     ok(psi != psi2, "ShellItems are of the same instance.\n");
3129                 if(SUCCEEDED(hr))
3130                 {
3131                     LPITEMIDLIST pidl1, pidl2;
3132                     hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl1);
3133                     ok(hr == S_OK, "Got 0x%08x\n", hr);
3134                     ok(pidl1 != NULL, "pidl1 was null.\n");
3135                     hr = pSHGetIDListFromObject((IUnknown*)psi2, &pidl2);
3136                     ok(hr == S_OK, "Got 0x%08x\n", hr);
3137                     ok(pidl2 != NULL, "pidl2 was null.\n");
3138                     ok(ILIsEqual(pidl1, pidl2), "pidls not equal.\n");
3139                     pILFree(pidl1);
3140                     pILFree(pidl2);
3141                     IShellItem_Release(psi2);
3142                 }
3143                 hr = IShellItemArray_GetItemAt(psia, 1, &psi2);
3144                 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3145                 IShellItemArray_Release(psia);
3146             }
3147             IShellItem_Release(psi);
3148         }
3149     }
3150     else
3151         skip("No SHCreateShellItemArrayFromShellItem.\n");
3152
3153     if(pSHCreateShellItemArrayFromDataObject)
3154     {
3155         IShellView *psv;
3156
3157         if(0)
3158         {
3159             /* Crashes under Windows 7 */
3160             hr = pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, NULL);
3161         }
3162         hr = pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, (void**)&psia);
3163         ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3164
3165         hr = IShellFolder_CreateViewObject(psf, NULL, &IID_IShellView, (void**)&psv);
3166         ok(hr == S_OK, "got 0x%08x\n", hr);
3167         if(SUCCEEDED(hr))
3168         {
3169             IEnumIDList *peidl;
3170             IDataObject *pdo;
3171             SHCONTF enum_flags;
3172
3173             enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3174             hr = IShellFolder_EnumObjects(psf, NULL, enum_flags, &peidl);
3175             ok(hr == S_OK, "got 0x%08x\n", hr);
3176             if(SUCCEEDED(hr))
3177             {
3178                 LPITEMIDLIST apidl[5];
3179                 UINT count, i;
3180
3181                 for(count = 0; count < 5; count++)
3182                     if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3183                         break;
3184                 ok(count == 5, "Got %d\n", count);
3185
3186                 if(count)
3187                 {
3188                     hr = IShellFolder_GetUIObjectOf(psf, NULL, count, (LPCITEMIDLIST*)apidl,
3189                                                     &IID_IDataObject, NULL, (void**)&pdo);
3190                     ok(hr == S_OK, "Got 0x%08x\n", hr);
3191                     if(SUCCEEDED(hr))
3192                     {
3193                         hr = pSHCreateShellItemArrayFromDataObject(pdo, &IID_IShellItemArray,
3194                                                                    (void**)&psia);
3195                         ok(hr == S_OK, "Got 0x%08x\n", hr);
3196                         if(SUCCEEDED(hr))
3197                         {
3198                             UINT count_sia, i;
3199                             hr = IShellItemArray_GetCount(psia, &count_sia);
3200                             ok(count_sia == count, "Counts differ (%d, %d)\n", count, count_sia);
3201                             for(i = 0; i < count_sia; i++)
3202                             {
3203                                 LPITEMIDLIST pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3204                                 IShellItem *psi;
3205                                 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3206                                 ok(hr == S_OK, "Got 0x%08x\n", hr);
3207                                 if(SUCCEEDED(hr))
3208                                 {
3209                                     LPITEMIDLIST pidl;
3210                                     hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3211                                     ok(hr == S_OK, "Got 0x%08x\n", hr);
3212                                     ok(pidl != NULL, "pidl as NULL.\n");
3213                                     ok(ILIsEqual(pidl, pidl_abs), "pidls differ.\n");
3214                                     pILFree(pidl);
3215                                     IShellItem_Release(psi);
3216                                 }
3217                                 pILFree(pidl_abs);
3218                             }
3219
3220                             IShellItemArray_Release(psia);
3221                         }
3222
3223                         IDataObject_Release(pdo);
3224                     }
3225                     for(i = 0; i < count; i++)
3226                         pILFree(apidl[i]);
3227                 }
3228                 else
3229                     skip("No files found - skipping test.\n");
3230
3231                 IEnumIDList_Release(peidl);
3232             }
3233             IShellView_Release(psv);
3234         }
3235     }
3236     else
3237         skip("No SHCreateShellItemArrayFromDataObject.\n");
3238
3239     IShellFolder_Release(psf);
3240     pILFree(pidl_testdir);
3241     Cleanup();
3242 }
3243
3244 static void test_ShellItemBindToHandler(void)
3245 {
3246     IShellItem *psi;
3247     LPITEMIDLIST pidl_desktop;
3248     HRESULT hr;
3249
3250     if(!pSHCreateShellItem)
3251     {
3252         skip("SHCreateShellItem missing.\n");
3253         return;
3254     }
3255
3256     hr = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3257     ok(hr == S_OK, "Got 0x%08x\n", hr);
3258     if(SUCCEEDED(hr))
3259     {
3260         hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
3261         ok(hr == S_OK, "Got 0x%08x\n", hr);
3262     }
3263     if(SUCCEEDED(hr))
3264     {
3265         IPersistFolder2 *ppf2;
3266         IUnknown *punk;
3267
3268         if(0)
3269         {
3270             /* Crashes under Windows 7 */
3271             hr = IShellItem_BindToHandler(psi, NULL, NULL, NULL, NULL);
3272             hr = IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, NULL);
3273         }
3274         hr = IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, (void**)&punk);
3275         ok(hr == MK_E_NOOBJECT, "Got 0x%08x\n", hr);
3276
3277         /* BHID_SFObject */
3278         hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IShellFolder, (void**)&punk);
3279         ok(hr == S_OK, "Got 0x%08x\n", hr);
3280         if(SUCCEEDED(hr)) IUnknown_Release(punk);
3281         hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IPersistFolder2, (void**)&ppf2);
3282         ok(hr == S_OK, "Got 0x%08x\n", hr);
3283         if(SUCCEEDED(hr))
3284         {
3285             LPITEMIDLIST pidl_tmp;
3286             hr = IPersistFolder2_GetCurFolder(ppf2, &pidl_tmp);
3287             ok(hr == S_OK, "Got 0x%08x\n", hr);
3288             if(SUCCEEDED(hr))
3289             {
3290                 ok(ILIsEqual(pidl_desktop, pidl_tmp), "Pidl not equal (%p, %p)\n", pidl_desktop, pidl_tmp);
3291                 pILFree(pidl_tmp);
3292             }
3293             IPersistFolder2_Release(ppf2);
3294         }
3295
3296         /* BHID_SFUIObject */
3297         hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IDataObject, (void**)&punk);
3298         ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3299         if(SUCCEEDED(hr)) IUnknown_Release(punk);
3300         hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IContextMenu, (void**)&punk);
3301         ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3302         if(SUCCEEDED(hr)) IUnknown_Release(punk);
3303
3304         /* BHID_DataObject */
3305         hr = IShellItem_BindToHandler(psi, NULL, &BHID_DataObject, &IID_IDataObject, (void**)&punk);
3306         ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3307         if(SUCCEEDED(hr)) IUnknown_Release(punk);
3308
3309         todo_wine
3310         {
3311             /* BHID_SFViewObject */
3312             hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellView, (void**)&punk);
3313             ok(hr == S_OK, "Got 0x%08x\n", hr);
3314             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3315             hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellFolderView, (void**)&punk);
3316             ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3317             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3318
3319             /* BHID_Storage */
3320             hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IStream, (void**)&punk);
3321             ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3322             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3323             hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IUnknown, (void**)&punk);
3324             ok(hr == S_OK, "Got 0x%08x\n", hr);
3325             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3326
3327             /* BHID_Stream */
3328             hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IStream, (void**)&punk);
3329             ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3330             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3331             hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IUnknown, (void**)&punk);
3332             ok(hr == S_OK, "Got 0x%08x\n", hr);
3333             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3334
3335             /* BHID_StorageEnum */
3336             hr = IShellItem_BindToHandler(psi, NULL, &BHID_StorageEnum, &IID_IEnumShellItems, (void**)&punk);
3337             ok(hr == S_OK, "Got 0x%08x\n", hr);
3338             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3339
3340             /* BHID_Transfer */
3341             hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_IUnknown, (void**)&punk);
3342             ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3343             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3344
3345             /* BHID_EnumItems */
3346             hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumItems, &IID_IEnumShellItems, (void**)&punk);
3347             ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3348             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3349
3350             /* BHID_Filter */
3351             hr = IShellItem_BindToHandler(psi, NULL, &BHID_Filter, &IID_IUnknown, (void**)&punk);
3352             ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3353             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3354
3355             /* BHID_LinkTargetItem */
3356             hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IShellItem, (void**)&punk);
3357             ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3358             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3359             hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IUnknown, (void**)&punk);
3360             ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3361             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3362
3363             /* BHID_PropertyStore */
3364             hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStore, (void**)&punk);
3365             ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3366             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3367             hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStoreFactory, (void**)&punk);
3368             ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3369             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3370
3371             /* BHID_ThumbnailHandler */
3372             hr = IShellItem_BindToHandler(psi, NULL, &BHID_ThumbnailHandler, &IID_IUnknown, (void**)&punk);
3373             ok(hr == E_INVALIDARG || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3374             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3375
3376             /* BHID_AssociationArray */
3377             hr = IShellItem_BindToHandler(psi, NULL, &BHID_AssociationArray, &IID_IQueryAssociations, (void**)&punk);
3378             ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3379             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3380
3381             /* BHID_EnumAssocHandlers */
3382             hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumAssocHandlers, &IID_IUnknown, (void**)&punk);
3383             ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3384             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3385         }
3386
3387         IShellItem_Release(psi);
3388     }
3389     else
3390         skip("Failed to create ShellItem.\n");
3391
3392     pILFree(pidl_desktop);
3393 }
3394
3395 static void test_SHParseDisplayName(void)
3396 {
3397     LPITEMIDLIST pidl1, pidl2;
3398     IShellFolder *desktop;
3399     WCHAR dirW[MAX_PATH];
3400     WCHAR nameW[10];
3401     HRESULT hr;
3402     BOOL ret;
3403
3404     if (!pSHParseDisplayName)
3405     {
3406         win_skip("SHParseDisplayName isn't available\n");
3407         return;
3408     }
3409
3410 if (0)
3411 {
3412     /* crashes on native */
3413     hr = pSHParseDisplayName(NULL, NULL, NULL, 0, NULL);
3414     nameW[0] = 0;
3415     hr = pSHParseDisplayName(nameW, NULL, NULL, 0, NULL);
3416 }
3417
3418     pidl1 = (LPITEMIDLIST)0xdeadbeef;
3419     hr = pSHParseDisplayName(NULL, NULL, &pidl1, 0, NULL);
3420     ok(broken(hr == E_OUTOFMEMORY) /* < Vista */ ||
3421        hr == E_INVALIDARG, "failed %08x\n", hr);
3422     ok(pidl1 == 0, "expected null ptr, got %p\n", pidl1);
3423
3424     /* dummy name */
3425     nameW[0] = 0;
3426     hr = pSHParseDisplayName(nameW, NULL, &pidl1, 0, NULL);
3427     ok(hr == S_OK, "failed %08x\n", hr);
3428     hr = SHGetDesktopFolder(&desktop);
3429     ok(hr == S_OK, "failed %08x\n", hr);
3430     hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, nameW, NULL, &pidl2, NULL);
3431     ok(hr == S_OK, "failed %08x\n", hr);
3432     ret = pILIsEqual(pidl1, pidl2);
3433     ok(ret == TRUE, "expected equal idls\n");
3434     pILFree(pidl1);
3435     pILFree(pidl2);
3436
3437     /* with path */
3438     GetWindowsDirectoryW( dirW, MAX_PATH );
3439
3440     hr = pSHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
3441     ok(hr == S_OK, "failed %08x\n", hr);
3442     hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, dirW, NULL, &pidl2, NULL);
3443     ok(hr == S_OK, "failed %08x\n", hr);
3444
3445     ret = pILIsEqual(pidl1, pidl2);
3446     ok(ret == TRUE, "expected equal idls\n");
3447     pILFree(pidl1);
3448     pILFree(pidl2);
3449
3450     IShellFolder_Release(desktop);
3451 }
3452
3453 static void test_desktop_IPersist(void)
3454 {
3455     IShellFolder *desktop;
3456     IPersist *persist;
3457     IPersistFolder2 *ppf2;
3458     CLSID clsid;
3459     HRESULT hr;
3460
3461     hr = SHGetDesktopFolder(&desktop);
3462     ok(hr == S_OK, "failed %08x\n", hr);
3463
3464     hr = IShellFolder_QueryInterface(desktop, &IID_IPersist, (void**)&persist);
3465     ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* NT4, W9X */, "failed %08x\n", hr);
3466
3467     if (hr == S_OK)
3468     {
3469     if (0)
3470     {
3471         /* crashes on native */
3472         hr = IPersist_GetClassID(persist, NULL);
3473     }
3474         memset(&clsid, 0, sizeof(clsid));
3475         hr = IPersist_GetClassID(persist, &clsid);
3476         ok(hr == S_OK, "failed %08x\n", hr);
3477         ok(IsEqualIID(&CLSID_ShellDesktop, &clsid), "Expected CLSID_ShellDesktop\n");
3478         IPersist_Release(persist);
3479     }
3480
3481     hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder2, (void**)&ppf2);
3482     ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* pre-Vista */, "failed %08x\n", hr);
3483     if(SUCCEEDED(hr))
3484     {
3485         IPersistFolder *ppf;
3486         LPITEMIDLIST pidl;
3487         hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder, (void**)&ppf);
3488         ok(hr == S_OK, "IID_IPersistFolder2 without IID_IPersistFolder.\n");
3489         if(SUCCEEDED(hr))
3490             IPersistFolder_Release(ppf);
3491
3492         todo_wine {
3493             hr = IPersistFolder2_Initialize(ppf2, NULL);
3494             ok(hr == S_OK, "got %08x\n", hr);
3495         }
3496
3497         pidl = NULL;
3498         hr = IPersistFolder2_GetCurFolder(ppf2, &pidl);
3499         ok(hr == S_OK, "got %08x\n", hr);
3500         ok(pidl != NULL, "pidl was NULL.\n");
3501         if(SUCCEEDED(hr)) pILFree(pidl);
3502
3503         IPersistFolder2_Release(ppf2);
3504     }
3505
3506     IShellFolder_Release(desktop);
3507 }
3508
3509 static void test_GetUIObject(void)
3510 {
3511     IShellFolder *psf_desktop;
3512     IContextMenu *pcm;
3513     LPITEMIDLIST pidl;
3514     HRESULT hr;
3515     WCHAR path[MAX_PATH];
3516     const WCHAR filename[] =
3517         {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
3518
3519     if(!pSHBindToParent)
3520     {
3521         win_skip("SHBindToParent missing.\n");
3522         return;
3523     }
3524
3525     GetCurrentDirectoryW(MAX_PATH, path);
3526     if(!lstrlenW(path))
3527     {
3528         skip("GetCurrentDirectoryW returned an empty string.\n");
3529         return;
3530     }
3531     lstrcatW(path, filename);
3532     SHGetDesktopFolder(&psf_desktop);
3533
3534     CreateFilesFolders();
3535
3536     hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, path, NULL, &pidl, 0);
3537     ok(hr == S_OK || broken(hr == E_FAIL) /* WinME */, "Got 0x%08x\n", hr);
3538     if(SUCCEEDED(hr))
3539     {
3540         IShellFolder *psf;
3541         LPCITEMIDLIST pidl_child;
3542         hr = pSHBindToParent(pidl, &IID_IShellFolder, (void**)&psf, &pidl_child);
3543         ok(hr == S_OK, "Got 0x%08x\n", hr);
3544         if(SUCCEEDED(hr))
3545         {
3546             hr = IShellFolder_GetUIObjectOf(psf, NULL, 1, (LPCITEMIDLIST*)&pidl_child,
3547                                             &IID_IContextMenu, NULL, (void**)&pcm);
3548             ok(hr == S_OK, "Got 0x%08x\n", hr);
3549             if(SUCCEEDED(hr))
3550             {
3551                 HMENU hmenu = CreatePopupMenu();
3552                 INT max_id, max_id_check;
3553                 UINT count, i;
3554                 const int id_upper_limit = 32767;
3555                 hr = IContextMenu_QueryContextMenu(pcm, hmenu, 0, 0, id_upper_limit, CMF_NORMAL);
3556                 ok(SUCCEEDED(hr), "Got 0x%08x\n", hr);
3557                 max_id = HRESULT_CODE(hr) - 1; /* returns max_id + 1 */
3558                 ok(max_id <= id_upper_limit, "Got %d\n", max_id);
3559                 count = GetMenuItemCount(hmenu);
3560                 ok(count, "Got %d\n", count);
3561
3562                 max_id_check = 0;
3563                 for(i = 0; i < count; i++)
3564                 {
3565                     MENUITEMINFOA mii;
3566                     INT res;
3567                     ZeroMemory(&mii, sizeof(MENUITEMINFOA));
3568                     mii.cbSize = sizeof(MENUITEMINFOA);
3569                     mii.fMask = MIIM_ID | MIIM_FTYPE;
3570
3571                     SetLastError(0);
3572                     res = GetMenuItemInfoA(hmenu, i, TRUE, &mii);
3573                     ok(res, "Failed (last error: %d).\n", GetLastError());
3574
3575                     ok( (mii.wID <= id_upper_limit) || (mii.fType & MFT_SEPARATOR),
3576                         "Got non-separator ID out of range: %d (type: %x)\n", mii.wID, mii.fType);
3577                     if(!(mii.fType & MFT_SEPARATOR))
3578                         max_id_check = (mii.wID>max_id_check)?mii.wID:max_id_check;
3579                 }
3580                 ok((max_id_check == max_id) ||
3581                    (max_id_check == max_id-1 /* Win 7 */),
3582                    "Not equal (or near equal), got %d and %d\n", max_id_check, max_id);
3583
3584 #define is_win2k() (pSHGetFolderPathA && !pSHGetFolderPathAndSubDirA)
3585
3586                 if(count && !is_win2k())   /* Test is interactive on w2k, so skip */
3587                 {
3588                     CMINVOKECOMMANDINFO cmi;
3589                     ZeroMemory(&cmi, sizeof(CMINVOKECOMMANDINFO));
3590                     cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
3591
3592                     /* Attempt to execute a nonexistent command */
3593                     cmi.lpVerb = MAKEINTRESOURCEA(9999);
3594                     hr = IContextMenu_InvokeCommand(pcm, &cmi);
3595                     ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3596
3597                     cmi.lpVerb = "foobar_wine_test";
3598                     hr = IContextMenu_InvokeCommand(pcm, &cmi);
3599                     ok( (hr == E_INVALIDARG) || (hr == E_FAIL /* Win7 */) ||
3600                         (hr == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION) /* Vista */),
3601                         "Got 0x%08x\n", hr);
3602                 }
3603 #undef is_win2k
3604
3605                 DestroyMenu(hmenu);
3606                 IContextMenu_Release(pcm);
3607             }
3608             IShellFolder_Release(psf);
3609         }
3610         if(pILFree) pILFree(pidl);
3611     }
3612
3613     IShellFolder_Release(psf_desktop);
3614     Cleanup();
3615 }
3616
3617 #define verify_pidl(i,p) r_verify_pidl(__LINE__, i, p)
3618 static void r_verify_pidl(unsigned l, LPCITEMIDLIST pidl, const WCHAR *path)
3619 {
3620     LPCITEMIDLIST child;
3621     IShellFolder *parent;
3622     STRRET filename;
3623     HRESULT hr;
3624
3625     if(!pSHBindToParent){
3626         win_skip("SHBindToParent is not available, not performing full PIDL verification\n");
3627         if(path)
3628             ok_(__FILE__,l)(pidl != NULL, "Expected PIDL to be non-NULL\n");
3629         else
3630             ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
3631         return;
3632     }
3633
3634     if(path){
3635         if(!pidl){
3636             ok_(__FILE__,l)(0, "didn't get expected path (%s), instead: NULL\n", wine_dbgstr_w(path));
3637             return;
3638         }
3639
3640         hr = pSHBindToParent(pidl, &IID_IShellFolder, (LPVOID*)&parent, &child);
3641         ok_(__FILE__,l)(hr == S_OK, "SHBindToParent failed: 0x%08x\n", hr);
3642         if(FAILED(hr))
3643             return;
3644
3645         hr = IShellFolder_GetDisplayNameOf(parent, child, SHGDN_FORPARSING, &filename);
3646         ok_(__FILE__,l)(hr == S_OK, "GetDisplayNameOf failed: 0x%08x\n", hr);
3647         if(FAILED(hr)){
3648             IShellFolder_Release(parent);
3649             return;
3650         }
3651
3652         ok_(__FILE__,l)(filename.uType == STRRET_WSTR || filename.uType == STRRET_CSTR,
3653                 "Got unexpected string type: %d\n", filename.uType);
3654         if(filename.uType == STRRET_WSTR){
3655             ok_(__FILE__,l)(lstrcmpW(path, U(filename).pOleStr) == 0,
3656                     "didn't get expected path (%s), instead: %s\n",
3657                      wine_dbgstr_w(path), wine_dbgstr_w(U(filename).pOleStr));
3658         }else if(filename.uType == STRRET_CSTR){
3659             ok_(__FILE__,l)(strcmp_wa(path, U(filename).cStr) == 0,
3660                     "didn't get expected path (%s), instead: %s\n",
3661                      wine_dbgstr_w(path), U(filename).cStr);
3662         }
3663
3664         IShellFolder_Release(parent);
3665     }else
3666         ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
3667 }
3668
3669 static void test_SHSimpleIDListFromPath(void)
3670 {
3671     const WCHAR adirW[] = {'C',':','\\','s','i','d','l','f','p','d','i','r',0};
3672     const CHAR adirA[] = "C:\\sidlfpdir";
3673     BOOL br, is_unicode = !(GetVersion() & 0x80000000);
3674
3675     LPITEMIDLIST pidl = NULL;
3676
3677     if(!pSHSimpleIDListFromPathAW){
3678         win_skip("SHSimpleIDListFromPathAW not available\n");
3679         return;
3680     }
3681
3682     br = CreateDirectoryA(adirA, NULL);
3683     ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
3684
3685     if(is_unicode)
3686         pidl = pSHSimpleIDListFromPathAW(adirW);
3687     else
3688         pidl = pSHSimpleIDListFromPathAW(adirA);
3689     verify_pidl(pidl, adirW);
3690     pILFree(pidl);
3691
3692     br = RemoveDirectoryA(adirA);
3693     ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
3694
3695     if(is_unicode)
3696         pidl = pSHSimpleIDListFromPathAW(adirW);
3697     else
3698         pidl = pSHSimpleIDListFromPathAW(adirA);
3699     verify_pidl(pidl, adirW);
3700     pILFree(pidl);
3701 }
3702
3703 /* IFileSystemBindData impl */
3704 static HRESULT WINAPI fsbd_QueryInterface(IFileSystemBindData *fsbd,
3705         REFIID riid, void **ppv)
3706 {
3707     if(IsEqualIID(riid, &IID_IFileSystemBindData) ||
3708             IsEqualIID(riid, &IID_IUnknown)){
3709         *ppv = fsbd;
3710         return S_OK;
3711     }
3712     return E_NOINTERFACE;
3713 }
3714
3715 static ULONG WINAPI fsbd_AddRef(IFileSystemBindData *fsbd)
3716 {
3717     return 2;
3718 }
3719
3720 static ULONG WINAPI fsbd_Release(IFileSystemBindData *fsbd)
3721 {
3722     return 1;
3723 }
3724
3725 static HRESULT WINAPI fsbd_SetFindData(IFileSystemBindData *fsbd,
3726         const WIN32_FIND_DATAW *pfd)
3727 {
3728     ok(0, "SetFindData called\n");
3729     return E_NOTIMPL;
3730 }
3731
3732 static HRESULT WINAPI fsbd_GetFindData_nul(IFileSystemBindData *fsbd,
3733         WIN32_FIND_DATAW *pfd)
3734 {
3735     memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
3736     return S_OK;
3737 }
3738
3739 static HRESULT WINAPI fsbd_GetFindData_junk(IFileSystemBindData *fsbd,
3740         WIN32_FIND_DATAW *pfd)
3741 {
3742     memset(pfd, 0xdeadbeef, sizeof(WIN32_FIND_DATAW));
3743     return S_OK;
3744 }
3745
3746 static HRESULT WINAPI fsbd_GetFindData_invalid(IFileSystemBindData *fsbd,
3747         WIN32_FIND_DATAW *pfd)
3748 {
3749     memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
3750     *pfd->cFileName = 'a';
3751     *pfd->cAlternateFileName = 'a';
3752     return S_OK;
3753 }
3754
3755 static HRESULT WINAPI fsbd_GetFindData_valid(IFileSystemBindData *fsbd,
3756         WIN32_FIND_DATAW *pfd)
3757 {
3758     static const WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
3759     HANDLE handle = FindFirstFileW(adirW, pfd);
3760     FindClose(handle);
3761     return S_OK;
3762 }
3763
3764 static HRESULT WINAPI fsbd_GetFindData_fail(IFileSystemBindData *fsbd,
3765         WIN32_FIND_DATAW *pfd)
3766 {
3767     return E_FAIL;
3768 }
3769
3770 static IFileSystemBindDataVtbl fsbdVtbl = {
3771     fsbd_QueryInterface,
3772     fsbd_AddRef,
3773     fsbd_Release,
3774     fsbd_SetFindData,
3775     NULL
3776 };
3777
3778 static IFileSystemBindData fsbd = { &fsbdVtbl };
3779
3780 static void test_ParseDisplayNamePBC(void)
3781 {
3782     WCHAR wFileSystemBindData[] =
3783         {'F','i','l','e',' ','S','y','s','t','e','m',' ','B','i','n','d',' ','D','a','t','a',0};
3784     WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
3785     const HRESULT exp_err = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
3786
3787     IShellFolder *psf;
3788     IBindCtx *pbc;
3789     HRESULT hres;
3790     ITEMIDLIST *pidl;
3791
3792     /* Check if we support WCHAR functions */
3793     SetLastError(0xdeadbeef);
3794     lstrcmpiW(adirW, adirW);
3795     if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED){
3796         win_skip("Most W-calls are not implemented\n");
3797         return;
3798     }
3799
3800     hres = SHGetDesktopFolder(&psf);
3801     ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
3802     if(FAILED(hres)){
3803         win_skip("Failed to get IShellFolder, can't run tests\n");
3804         return;
3805     }
3806
3807     /* fails on unknown dir with no IBindCtx */
3808     hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, adirW, NULL, &pidl, NULL);
3809     ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
3810             "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
3811
3812     /* fails on unknown dir with IBindCtx with no IFileSystemBindData */
3813     hres = CreateBindCtx(0, &pbc);
3814     ok(hres == S_OK, "CreateBindCtx failed: 0x%08x\n", hres);
3815
3816     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3817     ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
3818             "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
3819
3820     /* unknown dir with IBindCtx with IFileSystemBindData */
3821     hres = IBindCtx_RegisterObjectParam(pbc, wFileSystemBindData, (IUnknown*)&fsbd);
3822     ok(hres == S_OK, "RegisterObjectParam failed: 0x%08x\n", hres);
3823
3824     /* return E_FAIL from GetFindData */
3825     pidl = (ITEMIDLIST*)0xdeadbeef;
3826     fsbdVtbl.GetFindData = fsbd_GetFindData_fail;
3827     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3828     ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
3829             "ParseDisplayName failed: 0x%08x\n", hres);
3830     if(SUCCEEDED(hres)){
3831         verify_pidl(pidl, adirW);
3832         ILFree(pidl);
3833     }
3834
3835     /* set FIND_DATA struct to NULLs */
3836     pidl = (ITEMIDLIST*)0xdeadbeef;
3837     fsbdVtbl.GetFindData = fsbd_GetFindData_nul;
3838     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3839     ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
3840             "ParseDisplayName failed: 0x%08x\n", hres);
3841     if(SUCCEEDED(hres)){
3842         verify_pidl(pidl, adirW);
3843         ILFree(pidl);
3844     }
3845
3846     /* set FIND_DATA struct to junk */
3847     pidl = (ITEMIDLIST*)0xdeadbeef;
3848     fsbdVtbl.GetFindData = fsbd_GetFindData_junk;
3849     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3850     ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
3851             "ParseDisplayName failed: 0x%08x\n", hres);
3852     if(SUCCEEDED(hres)){
3853         verify_pidl(pidl, adirW);
3854         ILFree(pidl);
3855     }
3856
3857     /* set FIND_DATA struct to invalid data */
3858     pidl = (ITEMIDLIST*)0xdeadbeef;
3859     fsbdVtbl.GetFindData = fsbd_GetFindData_invalid;
3860     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3861     ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
3862             "ParseDisplayName failed: 0x%08x\n", hres);
3863     if(SUCCEEDED(hres)){
3864         verify_pidl(pidl, adirW);
3865         ILFree(pidl);
3866     }
3867
3868     /* set FIND_DATA struct to valid data */
3869     pidl = (ITEMIDLIST*)0xdeadbeef;
3870     fsbdVtbl.GetFindData = fsbd_GetFindData_valid;
3871     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3872     ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
3873             "ParseDisplayName failed: 0x%08x\n", hres);
3874     if(SUCCEEDED(hres)){
3875         verify_pidl(pidl, adirW);
3876         ILFree(pidl);
3877     }
3878
3879     IBindCtx_Release(pbc);
3880     IShellFolder_Release(psf);
3881 }
3882
3883 static const CHAR testwindow_class[] = "testwindow";
3884 #define WM_USER_NOTIFY (WM_APP+1)
3885
3886 static struct {
3887     const char *id;
3888     BOOL exp_notify;
3889     UINT signal;
3890     const WCHAR *path_1;
3891     const WCHAR *path_2;
3892 } exp_data;
3893
3894 static LRESULT CALLBACK testwindow_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
3895 {
3896     UINT signal = (UINT)lparam;
3897
3898     switch(msg){
3899     case WM_USER_NOTIFY:
3900         if(exp_data.exp_notify){
3901             LPCITEMIDLIST *pidls = (LPCITEMIDLIST*)wparam;
3902
3903             ok(exp_data.signal == signal,
3904                     "%s: expected notification type %x, got: %x\n",
3905                     exp_data.id, exp_data.signal, signal);
3906
3907             trace("verifying pidls for: %s\n", exp_data.id);
3908             verify_pidl(pidls[0], exp_data.path_1);
3909             verify_pidl(pidls[1], exp_data.path_2);
3910
3911             exp_data.exp_notify = FALSE;
3912         }else
3913             ok(exp_data.exp_notify, "Didn't expect a WM_USER_NOTIFY message (event: %x)\n", signal);
3914         return 0;
3915     }
3916     return DefWindowProc(hwnd, msg, wparam, lparam);
3917 }
3918
3919 static void register_testwindow_class(void)
3920 {
3921     WNDCLASSEXA cls;
3922     ATOM ret;
3923
3924     ZeroMemory(&cls, sizeof(cls));
3925     cls.cbSize = sizeof(cls);
3926     cls.style = 0;
3927     cls.lpfnWndProc = testwindow_wndproc;
3928     cls.hInstance = GetModuleHandleA(NULL);
3929     cls.lpszClassName = testwindow_class;
3930
3931     SetLastError(0);
3932     ret = RegisterClassExA(&cls);
3933     ok(ret != 0, "RegisterClassExA failed: %d\n", GetLastError());
3934 }
3935
3936 /* SHCNF_FLUSH doesn't seem to work as advertised for SHCNF_PATHA, so we
3937  * have to poll repeatedly for the message to appear */
3938 static void do_events(void)
3939 {
3940     int c = 0;
3941     while (exp_data.exp_notify && (c++ < 10)){
3942         MSG msg;
3943         while(PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)){
3944             TranslateMessage(&msg);
3945             DispatchMessageA(&msg);
3946         }
3947         if(exp_data.exp_notify)
3948             Sleep(500);
3949     }
3950     trace("%s: took %d tries\n", exp_data.id, c);
3951 }
3952
3953 static void test_SHChangeNotify(void)
3954 {
3955     HWND wnd;
3956     ULONG notifyID;
3957     HRESULT hr;
3958     BOOL br, has_unicode;
3959     SHChangeNotifyEntry entries[1];
3960     const CHAR root_dirA[] = "C:\\shell32_cn_test";
3961     const WCHAR root_dirW[] = {'C',':','\\','s','h','e','l','l','3','2','_','c','n','_','t','e','s','t',0};
3962     const CHAR test_dirA[] = "C:\\shell32_cn_test\\test";
3963     const WCHAR test_dirW[] = {'C',':','\\','s','h','e','l','l','3','2','_','c','n','_','t','e','s','t','\\','t','e','s','t',0};
3964
3965     CreateDirectoryW(NULL, NULL);
3966     has_unicode = !(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED);
3967
3968     /* set up the root directory & window */
3969     br = CreateDirectoryA(root_dirA, NULL);
3970     ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
3971
3972     register_testwindow_class();
3973
3974     wnd = CreateWindowExA(0, testwindow_class, testwindow_class, 0,
3975             CW_USEDEFAULT, CW_USEDEFAULT, 130, 105,
3976             NULL, NULL, GetModuleHandleA(NULL), 0);
3977     ok(wnd != NULL, "Failed to make a window\n");
3978
3979     entries[0].pidl = NULL;
3980     if(has_unicode)
3981         hr = SHILCreateFromPath(root_dirW, (LPITEMIDLIST*)&entries[0].pidl, 0);
3982     else
3983         hr = SHILCreateFromPath((LPCVOID)root_dirA, (LPITEMIDLIST*)&entries[0].pidl, 0);
3984     ok(hr == S_OK, "SHILCreateFromPath failed: 0x%08x\n", hr);
3985     entries[0].fRecursive = TRUE;
3986
3987     notifyID = SHChangeNotifyRegister(wnd, SHCNRF_ShellLevel,
3988             SHCNE_ALLEVENTS, WM_USER_NOTIFY, 1, entries);
3989     ok(notifyID != 0, "Failed to register a window for change notifications\n");
3990
3991     /* MKDIR */
3992     br = CreateDirectoryA(test_dirA, NULL);
3993     ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
3994
3995     if(has_unicode){
3996         exp_data.id = "MKDIR PATHW";
3997         exp_data.signal = SHCNE_MKDIR;
3998         exp_data.exp_notify = TRUE;
3999         exp_data.path_1 = test_dirW;
4000         exp_data.path_2 = NULL;
4001         SHChangeNotify(SHCNE_MKDIR, SHCNF_PATHW | SHCNF_FLUSH, test_dirW, NULL);
4002         do_events();
4003         ok(exp_data.exp_notify == FALSE, "Expected wndproc to be called\n");
4004     }else
4005         win_skip("skipping WCHAR tests\n");
4006
4007     exp_data.id = "MKDIR PATHA";
4008     exp_data.signal = SHCNE_MKDIR;
4009     exp_data.exp_notify = TRUE;
4010     exp_data.path_1 = test_dirW;
4011     exp_data.path_2 = NULL;
4012     SHChangeNotify(SHCNE_MKDIR, SHCNF_PATHA | SHCNF_FLUSH, test_dirA, NULL);
4013     do_events();
4014     ok(exp_data.exp_notify == FALSE, "Expected wndproc to be called\n");
4015
4016     /* RMDIR */
4017     br = RemoveDirectoryA(test_dirA);
4018     ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4019
4020     if(has_unicode){
4021         exp_data.id = "RMDIR PATHW";
4022         exp_data.signal = SHCNE_RMDIR;
4023         exp_data.exp_notify = TRUE;
4024         exp_data.path_1 = test_dirW;
4025         exp_data.path_2 = NULL;
4026         SHChangeNotify(SHCNE_RMDIR, SHCNF_PATHW | SHCNF_FLUSH, test_dirW, NULL);
4027         do_events();
4028         ok(exp_data.exp_notify == FALSE, "Expected wndproc to be called\n");
4029     }else
4030         win_skip("skipping WCHAR tests\n");
4031
4032     exp_data.id = "RMDIR PATHA";
4033     exp_data.signal = SHCNE_RMDIR;
4034     exp_data.exp_notify = TRUE;
4035     exp_data.path_1 = test_dirW;
4036     exp_data.path_2 = NULL;
4037     SHChangeNotify(SHCNE_RMDIR, SHCNF_PATHA | SHCNF_FLUSH, test_dirA, NULL);
4038     do_events();
4039     ok(exp_data.exp_notify == FALSE, "Expected wndproc to be called\n");
4040
4041     SHChangeNotifyDeregister(notifyID);
4042     DestroyWindow(wnd);
4043
4044     br = RemoveDirectoryA(root_dirA);
4045     ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4046 }
4047
4048 START_TEST(shlfolder)
4049 {
4050     init_function_pointers();
4051     /* if OleInitialize doesn't get called, ParseDisplayName returns
4052        CO_E_NOTINITIALIZED for malformed directory names on win2k. */
4053     OleInitialize(NULL);
4054
4055     test_ParseDisplayName();
4056     test_SHParseDisplayName();
4057     test_BindToObject();
4058     test_EnumObjects_and_CompareIDs();
4059     test_GetDisplayName();
4060     test_GetAttributesOf();
4061     test_SHGetPathFromIDList();
4062     test_CallForAttributes();
4063     test_FolderShortcut();
4064     test_ITEMIDLIST_format();
4065     test_SHGetFolderPathAndSubDirA();
4066     test_LocalizedNames();
4067     test_SHCreateShellItem();
4068     test_SHCreateShellItemArray();
4069     test_desktop_IPersist();
4070     test_GetUIObject();
4071     test_SHSimpleIDListFromPath();
4072     test_ParseDisplayNamePBC();
4073     test_SHGetNameFromIDList();
4074     test_SHGetItemFromDataObject();
4075     test_SHGetIDListFromObject();
4076     test_SHGetItemFromObject();
4077     test_ShellItemCompare();
4078     test_SHChangeNotify();
4079     test_ShellItemBindToHandler();
4080
4081     OleUninitialize();
4082 }