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