shell32/tests: Fix some test failures on Vista and higher.
[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
43 static IMalloc *ppM;
44
45 static HRESULT (WINAPI *pSHBindToParent)(LPCITEMIDLIST, REFIID, LPVOID*, LPCITEMIDLIST*);
46 static HRESULT (WINAPI *pSHGetFolderPathA)(HWND, int, HANDLE, DWORD, LPSTR);
47 static HRESULT (WINAPI *pSHGetFolderPathAndSubDirA)(HWND, int, HANDLE, DWORD, LPCSTR, LPSTR);
48 static BOOL (WINAPI *pSHGetPathFromIDListW)(LPCITEMIDLIST,LPWSTR);
49 static BOOL (WINAPI *pSHGetSpecialFolderPathA)(HWND, LPSTR, int, BOOL);
50 static BOOL (WINAPI *pSHGetSpecialFolderPathW)(HWND, LPWSTR, int, BOOL);
51 static HRESULT (WINAPI *pStrRetToBufW)(STRRET*,LPCITEMIDLIST,LPWSTR,UINT);
52 static LPITEMIDLIST (WINAPI *pILFindLastID)(LPCITEMIDLIST);
53 static void (WINAPI *pILFree)(LPITEMIDLIST);
54 static BOOL (WINAPI *pILIsEqual)(LPCITEMIDLIST, LPCITEMIDLIST);
55 static HRESULT (WINAPI *pSHCreateShellItem)(LPCITEMIDLIST,IShellFolder*,LPCITEMIDLIST,IShellItem**);
56 static LPITEMIDLIST (WINAPI *pILCombine)(LPCITEMIDLIST,LPCITEMIDLIST);
57
58
59 static void init_function_pointers(void)
60 {
61     HMODULE hmod;
62     HRESULT hr;
63
64     hmod = GetModuleHandleA("shell32.dll");
65     pSHBindToParent = (void*)GetProcAddress(hmod, "SHBindToParent");
66     pSHGetFolderPathA = (void*)GetProcAddress(hmod, "SHGetFolderPathA");
67     pSHGetFolderPathAndSubDirA = (void*)GetProcAddress(hmod, "SHGetFolderPathAndSubDirA");
68     pSHGetPathFromIDListW = (void*)GetProcAddress(hmod, "SHGetPathFromIDListW");
69     pSHGetSpecialFolderPathA = (void*)GetProcAddress(hmod, "SHGetSpecialFolderPathA");
70     pSHGetSpecialFolderPathW = (void*)GetProcAddress(hmod, "SHGetSpecialFolderPathW");
71     pILFindLastID = (void *)GetProcAddress(hmod, (LPCSTR)16);
72     pILFree = (void*)GetProcAddress(hmod, (LPSTR)155);
73     pILIsEqual = (void*)GetProcAddress(hmod, (LPSTR)21);
74     pSHCreateShellItem = (void*)GetProcAddress(hmod, "SHCreateShellItem");
75     pILCombine = (void*)GetProcAddress(hmod, (LPSTR)25);
76
77     hmod = GetModuleHandleA("shlwapi.dll");
78     pStrRetToBufW = (void*)GetProcAddress(hmod, "StrRetToBufW");
79
80     hr = SHGetMalloc(&ppM);
81     ok(hr == S_OK, "SHGetMalloc failed %08x\n", hr);
82 }
83
84 static const char *wine_dbgstr_w(LPCWSTR str)
85 {
86     static char buf[512];
87     if (!str)
88         return "(null)";
89     WideCharToMultiByte(CP_ACP, 0, str, -1, buf, sizeof(buf), NULL, NULL);
90     return buf;
91 }
92
93 static void test_ParseDisplayName(void)
94 {
95     HRESULT hr;
96     IShellFolder *IDesktopFolder;
97     static const char *cNonExistDir1A = "c:\\nonexist_subdir";
98     static const char *cNonExistDir2A = "c:\\\\nonexist_subdir";
99     static const char *cInetTestA = "http:\\yyy";
100     static const char *cInetTest2A = "xx:yyy";
101     DWORD res;
102     WCHAR cTestDirW [MAX_PATH] = {0};
103     ITEMIDLIST *newPIDL;
104     BOOL bRes;
105
106     hr = SHGetDesktopFolder(&IDesktopFolder);
107     if(hr != S_OK) return;
108
109     MultiByteToWideChar(CP_ACP, 0, cInetTestA, -1, cTestDirW, MAX_PATH);
110     hr = IShellFolder_ParseDisplayName(IDesktopFolder,
111         NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
112     todo_wine ok((SUCCEEDED(hr) || broken(hr == E_FAIL) /* NT4 */),
113         "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
114     if (SUCCEEDED(hr))
115     {
116         ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
117            "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
118         IMalloc_Free(ppM, newPIDL);
119     }
120
121     MultiByteToWideChar(CP_ACP, 0, cInetTest2A, -1, cTestDirW, MAX_PATH);
122     hr = IShellFolder_ParseDisplayName(IDesktopFolder,
123         NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
124     todo_wine ok((SUCCEEDED(hr) || broken(hr == E_FAIL) /* NT4 */),
125         "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
126     if (SUCCEEDED(hr))
127     {
128         ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
129            "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
130         IMalloc_Free(ppM, newPIDL);
131     }
132
133     res = GetFileAttributesA(cNonExistDir1A);
134     if(res != INVALID_FILE_ATTRIBUTES) return;
135
136     MultiByteToWideChar(CP_ACP, 0, cNonExistDir1A, -1, cTestDirW, MAX_PATH);
137     hr = IShellFolder_ParseDisplayName(IDesktopFolder, 
138         NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
139     ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL), 
140         "ParseDisplayName returned %08x, expected 80070002 or E_FAIL\n", hr);
141
142     res = GetFileAttributesA(cNonExistDir2A);
143     if(res != INVALID_FILE_ATTRIBUTES) return;
144
145     MultiByteToWideChar(CP_ACP, 0, cNonExistDir2A, -1, cTestDirW, MAX_PATH);
146     hr = IShellFolder_ParseDisplayName(IDesktopFolder, 
147         NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
148     ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL) || (hr == E_INVALIDARG), 
149         "ParseDisplayName returned %08x, expected 80070002, E_FAIL or E_INVALIDARG\n", hr);
150
151     /* I thought that perhaps the DesktopFolder's ParseDisplayName would recognize the
152      * path corresponding to CSIDL_PERSONAL and return a CLSID_MyDocuments PIDL. Turns
153      * out it doesn't. The magic seems to happen in the file dialogs, then. */
154     if (!pSHGetSpecialFolderPathW || !pILFindLastID) goto finished;
155     
156     bRes = pSHGetSpecialFolderPathW(NULL, cTestDirW, CSIDL_PERSONAL, FALSE);
157     ok(bRes, "SHGetSpecialFolderPath(CSIDL_PERSONAL) failed! %u\n", GetLastError());
158     if (!bRes) goto finished;
159
160     hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
161     ok(SUCCEEDED(hr), "DesktopFolder->ParseDisplayName failed. hr = %08x.\n", hr);
162     if (FAILED(hr)) goto finished;
163
164     ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x31 ||
165        pILFindLastID(newPIDL)->mkid.abID[0] == 0xb1, /* Win98 */
166        "Last pidl should be of type PT_FOLDER or PT_IESPECIAL2, but is: %02x\n",
167        pILFindLastID(newPIDL)->mkid.abID[0]);
168     IMalloc_Free(ppM, newPIDL);
169     
170 finished:
171     IShellFolder_Release(IDesktopFolder);
172 }
173
174 /* creates a file with the specified name for tests */
175 static void CreateTestFile(const CHAR *name)
176 {
177     HANDLE file;
178     DWORD written;
179
180     file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
181     if (file != INVALID_HANDLE_VALUE)
182     {
183         WriteFile(file, name, strlen(name), &written, NULL);
184         WriteFile(file, "\n", strlen("\n"), &written, NULL);
185         CloseHandle(file);
186     }
187 }
188
189
190 /* initializes the tests */
191 static void CreateFilesFolders(void)
192 {
193     CreateDirectoryA(".\\testdir", NULL);
194     CreateDirectoryA(".\\testdir\\test.txt", NULL);
195     CreateTestFile  (".\\testdir\\test1.txt ");
196     CreateTestFile  (".\\testdir\\test2.txt ");
197     CreateTestFile  (".\\testdir\\test3.txt ");
198     CreateDirectoryA(".\\testdir\\testdir2 ", NULL);
199     CreateDirectoryA(".\\testdir\\testdir2\\subdir", NULL);
200 }
201
202 /* cleans after tests */
203 static void Cleanup(void)
204 {
205     DeleteFileA(".\\testdir\\test1.txt");
206     DeleteFileA(".\\testdir\\test2.txt");
207     DeleteFileA(".\\testdir\\test3.txt");
208     RemoveDirectoryA(".\\testdir\\test.txt");
209     RemoveDirectoryA(".\\testdir\\testdir2\\subdir");
210     RemoveDirectoryA(".\\testdir\\testdir2");
211     RemoveDirectoryA(".\\testdir");
212 }
213
214
215 /* perform test */
216 static void test_EnumObjects(IShellFolder *iFolder)
217 {
218     IEnumIDList *iEnumList;
219     LPITEMIDLIST newPIDL, idlArr[10];
220     ULONG NumPIDLs;
221     int i=0, j;
222     HRESULT hr;
223
224     static const WORD iResults [5][5] =
225     {
226         { 0,-1,-1,-1,-1},
227         { 1, 0,-1,-1,-1},
228         { 1, 1, 0,-1,-1},
229         { 1, 1, 1, 0,-1},
230         { 1, 1, 1, 1, 0}
231     };
232
233 #define SFGAO_testfor SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | SFGAO_CAPABILITYMASK
234     /* Don't test for SFGAO_HASSUBFOLDER since we return real state and native cached */
235     static const ULONG attrs[5] =
236     {
237         SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
238         SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
239         SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
240         SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
241         SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
242     };
243
244     hr = IShellFolder_EnumObjects(iFolder, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &iEnumList);
245     ok(hr == S_OK, "EnumObjects failed %08x\n", hr);
246
247     /* This is to show that, contrary to what is said on MSDN, on IEnumIDList::Next,
248      * the filesystem shellfolders return S_OK even if less than 'celt' items are
249      * returned (in contrast to S_FALSE). We have to do it in a loop since WinXP
250      * only ever returns a single entry per call. */
251     while (IEnumIDList_Next(iEnumList, 10-i, &idlArr[i], &NumPIDLs) == S_OK) 
252         i += NumPIDLs;
253     ok (i == 5, "i: %d\n", i);
254
255     hr = IEnumIDList_Release(iEnumList);
256     ok(hr == S_OK, "IEnumIDList_Release failed %08x\n", hr);
257     
258     /* Sort them first in case of wrong order from system */
259     for (i=0;i<5;i++) for (j=0;j<5;j++)
260         if ((SHORT)IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]) < 0)
261         {
262             newPIDL = idlArr[i];
263             idlArr[i] = idlArr[j];
264             idlArr[j] = newPIDL;
265         }
266             
267     for (i=0;i<5;i++) for (j=0;j<5;j++)
268     {
269         hr = IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]);
270         ok(hr == iResults[i][j], "Got %x expected [%d]-[%d]=%x\n", hr, i, j, iResults[i][j]);
271     }
272
273
274     for (i = 0; i < 5; i++)
275     {
276         SFGAOF flags;
277         /* Native returns all flags no matter what we ask for */
278         flags = SFGAO_CANCOPY;
279         hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
280         flags &= SFGAO_testfor;
281         ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
282         ok(flags == (attrs[i]) ||
283            flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR), /* Win9x, NT4 */
284            "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
285
286         flags = SFGAO_testfor;
287         hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
288         flags &= SFGAO_testfor;
289         ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
290         ok(flags == attrs[i] ||
291            flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR), /* Win9x, NT4 */
292            "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
293     }
294
295     for (i=0;i<5;i++)
296         IMalloc_Free(ppM, idlArr[i]);
297 }
298
299 static void test_BindToObject(void)
300 {
301     HRESULT hr;
302     UINT cChars;
303     IShellFolder *psfDesktop, *psfChild, *psfMyComputer, *psfSystemDir;
304     SHITEMID emptyitem = { 0, { 0 } };
305     LPITEMIDLIST pidlMyComputer, pidlSystemDir, pidlEmpty = (LPITEMIDLIST)&emptyitem;
306     WCHAR wszSystemDir[MAX_PATH];
307     char szSystemDir[MAX_PATH];
308     WCHAR wszMyComputer[] = { 
309         ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
310         'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
311
312     /* The following tests shows that BindToObject should fail with E_INVALIDARG if called
313      * with an empty pidl. This is tested for Desktop, MyComputer and the FS ShellFolder
314      */
315     hr = SHGetDesktopFolder(&psfDesktop);
316     ok (SUCCEEDED(hr), "SHGetDesktopFolder failed! hr = %08x\n", hr);
317     if (FAILED(hr)) return;
318     
319     hr = IShellFolder_BindToObject(psfDesktop, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
320     ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
321
322     hr = IShellFolder_BindToObject(psfDesktop, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
323     ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
324
325     hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
326     ok (SUCCEEDED(hr), "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
327     if (FAILED(hr)) {
328         IShellFolder_Release(psfDesktop);
329         return;
330     }
331     
332     hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
333     ok (SUCCEEDED(hr), "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
334     IShellFolder_Release(psfDesktop);
335     IMalloc_Free(ppM, pidlMyComputer);
336     if (FAILED(hr)) return;
337
338     hr = IShellFolder_BindToObject(psfMyComputer, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
339     ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
340
341 #if 0
342     /* this call segfaults on 98SE */
343     hr = IShellFolder_BindToObject(psfMyComputer, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
344     ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
345 #endif
346
347     cChars = GetSystemDirectoryA(szSystemDir, MAX_PATH);
348     ok (cChars > 0 && cChars < MAX_PATH, "GetSystemDirectoryA failed! LastError: %u\n", GetLastError());
349     if (cChars == 0 || cChars >= MAX_PATH) {
350         IShellFolder_Release(psfMyComputer);
351         return;
352     }
353     MultiByteToWideChar(CP_ACP, 0, szSystemDir, -1, wszSystemDir, MAX_PATH);
354     
355     hr = IShellFolder_ParseDisplayName(psfMyComputer, NULL, NULL, wszSystemDir, NULL, &pidlSystemDir, NULL);
356     ok (SUCCEEDED(hr), "MyComputers's ParseDisplayName failed to parse the SystemDirectory! hr = %08x\n", hr);
357     if (FAILED(hr)) {
358         IShellFolder_Release(psfMyComputer);
359         return;
360     }
361
362     hr = IShellFolder_BindToObject(psfMyComputer, pidlSystemDir, NULL, &IID_IShellFolder, (LPVOID*)&psfSystemDir);
363     ok (SUCCEEDED(hr), "MyComputer failed to bind to a FileSystem ShellFolder! hr = %08x\n", hr);
364     IShellFolder_Release(psfMyComputer);
365     IMalloc_Free(ppM, pidlSystemDir);
366     if (FAILED(hr)) return;
367
368     hr = IShellFolder_BindToObject(psfSystemDir, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
369     ok (hr == E_INVALIDARG, 
370         "FileSystem ShellFolder's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
371     
372 #if 0
373     /* this call segfaults on 98SE */
374     hr = IShellFolder_BindToObject(psfSystemDir, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
375     ok (hr == E_INVALIDARG, 
376         "FileSystem ShellFolder's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
377 #endif
378
379     IShellFolder_Release(psfSystemDir);
380 }
381
382 /* Based on PathAddBackslashW from dlls/shlwapi/path.c */
383 static LPWSTR myPathAddBackslashW( LPWSTR lpszPath )
384 {
385   size_t iLen;
386
387   if (!lpszPath || (iLen = lstrlenW(lpszPath)) >= MAX_PATH)
388     return NULL;
389
390   if (iLen)
391   {
392     lpszPath += iLen;
393     if (lpszPath[-1] != '\\')
394     {
395       *lpszPath++ = '\\';
396       *lpszPath = '\0';
397     }
398   }
399   return lpszPath;
400 }
401
402 static void test_GetDisplayName(void)
403 {
404     BOOL result;
405     HRESULT hr;
406     HANDLE hTestFile;
407     WCHAR wszTestFile[MAX_PATH], wszTestFile2[MAX_PATH];
408     char szTestFile[MAX_PATH], szTestDir[MAX_PATH];
409     DWORD attr;
410     STRRET strret;
411     LPSHELLFOLDER psfDesktop, psfPersonal;
412     IUnknown *psfFile;
413     SHITEMID emptyitem = { 0, { 0 } };
414     LPITEMIDLIST pidlTestFile, pidlEmpty = (LPITEMIDLIST)&emptyitem;
415     LPCITEMIDLIST pidlLast;
416     static const CHAR szFileName[] = "winetest.foo";
417     static const WCHAR wszFileName[] = { 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
418     static const WCHAR wszDirName[] = { 'w','i','n','e','t','e','s','t',0 };
419
420     /* I'm trying to figure if there is a functional difference between calling
421      * SHGetPathFromIDListW and calling GetDisplayNameOf(SHGDN_FORPARSING) after
422      * binding to the shellfolder. One thing I thought of was that perhaps 
423      * SHGetPathFromIDListW would be able to get the path to a file, which does
424      * not exist anymore, while the other method wouldn't. It turns out there's
425      * no functional difference in this respect.
426      */
427
428     if(!pSHGetSpecialFolderPathA) {
429         win_skip("SHGetSpecialFolderPathA is not available\n");
430         return;
431     }
432
433     /* First creating a directory in MyDocuments and a file in this directory. */
434     result = pSHGetSpecialFolderPathA(NULL, szTestDir, CSIDL_PERSONAL, FALSE);
435     ok(result, "SHGetSpecialFolderPathA failed! Last error: %u\n", GetLastError());
436     if (!result) return;
437
438     /* Use ANSI file functions so this works on Windows 9x */
439     lstrcatA(szTestDir, "\\winetest");
440     CreateDirectoryA(szTestDir, NULL);
441     attr=GetFileAttributesA(szTestDir);
442     if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY))
443     {
444         ok(0, "unable to create the '%s' directory\n", szTestDir);
445         return;
446     }
447
448     lstrcpyA(szTestFile, szTestDir);
449     lstrcatA(szTestFile, "\\");
450     lstrcatA(szTestFile, szFileName);
451     hTestFile = CreateFileA(szTestFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
452     ok((hTestFile != INVALID_HANDLE_VALUE), "CreateFileA failed! Last error: %u\n", GetLastError());
453     if (hTestFile == INVALID_HANDLE_VALUE) return;
454     CloseHandle(hTestFile);
455
456     /* Getting an itemidlist for the file. */
457     hr = SHGetDesktopFolder(&psfDesktop);
458     ok(SUCCEEDED(hr), "SHGetDesktopFolder failed! hr = %08x\n", hr);
459     if (FAILED(hr)) return;
460
461     MultiByteToWideChar(CP_ACP, 0, szTestFile, -1, wszTestFile, MAX_PATH);
462
463     hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
464     ok(SUCCEEDED(hr), "Desktop->ParseDisplayName failed! hr = %08x\n", hr);
465     if (FAILED(hr)) {
466         IShellFolder_Release(psfDesktop);
467         return;
468     }
469
470     pidlLast = pILFindLastID(pidlTestFile);
471     ok(pidlLast->mkid.cb >=76 ||
472         broken(pidlLast->mkid.cb == 28) || /* W2K */
473         broken(pidlLast->mkid.cb == 40), /* Win9x, WinME */
474         "Expected pidl length of at least 76, got %d.\n", pidlLast->mkid.cb);
475     if (pidlLast->mkid.cb >= 28) {
476         ok(!lstrcmpA((CHAR*)&pidlLast->mkid.abID[12], szFileName),
477             "Filename should be stored as ansi-string at this position!\n");
478     }
479     /* WinXP and up store the filenames as both ANSI and UNICODE in the pidls */
480     if (pidlLast->mkid.cb >= 76) {
481         ok(!lstrcmpW((WCHAR*)&pidlLast->mkid.abID[46], wszFileName) ||
482             (pidlLast->mkid.cb >= 94 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[64], wszFileName)), /* Vista */
483             "Filename should be stored as wchar-string at this position!\n");
484     }
485     
486     /* It seems as if we cannot bind to regular files on windows, but only directories. 
487      */
488     hr = IShellFolder_BindToObject(psfDesktop, pidlTestFile, NULL, &IID_IUnknown, (VOID**)&psfFile);
489     todo_wine
490     ok (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
491         hr == E_NOTIMPL || /* Vista */
492         broken(SUCCEEDED(hr)), /* Win9x, W2K */
493         "hr = %08x\n", hr);
494     if (SUCCEEDED(hr)) {
495         IShellFolder_Release(psfFile);
496     }
497
498     if (!pSHBindToParent)
499     {
500         win_skip("SHBindToParent is missing\n");
501         DeleteFileA(szTestFile);
502         RemoveDirectoryA(szTestDir);
503         return;
504     }
505   
506     /* Some tests for IShellFolder::SetNameOf */
507     if (pSHGetFolderPathAndSubDirA)
508     {
509         hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
510         ok(SUCCEEDED(hr), "SHBindToParent failed! hr = %08x\n", hr);
511         if (SUCCEEDED(hr)) {
512             /* It's ok to use this fixed path. Call will fail anyway. */
513             WCHAR wszAbsoluteFilename[] = { 'C',':','\\','w','i','n','e','t','e','s','t', 0 };
514             LPITEMIDLIST pidlNew;
515
516             /* The pidl returned through the last parameter of SetNameOf is a simple one. */
517             hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlLast, wszDirName, SHGDN_NORMAL, &pidlNew);
518             ok (SUCCEEDED(hr), "SetNameOf failed! hr = %08x\n", hr);
519             if (hr == S_OK)
520             {
521                 ok (((LPITEMIDLIST)((LPBYTE)pidlNew+pidlNew->mkid.cb))->mkid.cb == 0,
522                     "pidl returned from SetNameOf should be simple!\n");
523
524                 /* Passing an absolute path to SetNameOf fails. The HRESULT code indicates that SetNameOf
525                  * is implemented on top of SHFileOperation in WinXP. */
526                 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszAbsoluteFilename,
527                         SHGDN_FORPARSING, NULL);
528                 ok (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED), "SetNameOf succeeded! hr = %08x\n", hr);
529
530                 /* Rename the file back to its original name. SetNameOf ignores the fact, that the
531                  * SHGDN flags specify an absolute path. */
532                 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszFileName, SHGDN_FORPARSING, NULL);
533                 ok (SUCCEEDED(hr), "SetNameOf failed! hr = %08x\n", hr);
534
535                 pILFree(pidlNew);
536             }
537
538             IShellFolder_Release(psfPersonal);
539         }
540     }
541     else
542         win_skip("Avoid needs of interaction on Win2k\n");
543
544     /* Deleting the file and the directory */
545     DeleteFileA(szTestFile);
546     RemoveDirectoryA(szTestDir);
547
548     /* SHGetPathFromIDListW still works, although the file is not present anymore. */
549     if (pSHGetPathFromIDListW)
550     {
551         result = pSHGetPathFromIDListW(pidlTestFile, wszTestFile2);
552         ok (result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
553         ok (!lstrcmpiW(wszTestFile, wszTestFile2), "SHGetPathFromIDListW returns incorrect path!\n");
554     }
555
556     /* SHBindToParent fails, if called with a NULL PIDL. */
557     hr = pSHBindToParent(NULL, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
558     ok (FAILED(hr), "SHBindToParent(NULL) should fail!\n");
559
560     /* But it succeeds with an empty PIDL. */
561     hr = pSHBindToParent(pidlEmpty, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
562     ok (SUCCEEDED(hr), "SHBindToParent(empty PIDL) should succeed! hr = %08x\n", hr);
563     ok (pidlLast == pidlEmpty, "The last element of an empty PIDL should be the PIDL itself!\n");
564     if (SUCCEEDED(hr)) 
565         IShellFolder_Release(psfPersonal);
566     
567     /* Binding to the folder and querying the display name of the file also works. */
568     hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast); 
569     ok (SUCCEEDED(hr), "SHBindToParent failed! hr = %08x\n", hr);
570     if (FAILED(hr)) {
571         IShellFolder_Release(psfDesktop);
572         return;
573     }
574
575     /* This test shows that Windows doesn't allocate a new pidlLast, but returns a pointer into 
576      * pidlTestFile (In accordance with MSDN). */
577     ok (pILFindLastID(pidlTestFile) == pidlLast, 
578                                 "SHBindToParent doesn't return the last id of the pidl param!\n");
579     
580     hr = IShellFolder_GetDisplayNameOf(psfPersonal, pidlLast, SHGDN_FORPARSING, &strret);
581     ok (SUCCEEDED(hr), "Personal->GetDisplayNameOf failed! hr = %08x\n", hr);
582     if (FAILED(hr)) {
583         IShellFolder_Release(psfDesktop);
584         IShellFolder_Release(psfPersonal);
585         return;
586     }
587
588     if (pStrRetToBufW)
589     {
590         hr = pStrRetToBufW(&strret, pidlLast, wszTestFile2, MAX_PATH);
591         ok (SUCCEEDED(hr), "StrRetToBufW failed! hr = %08x\n", hr);
592         ok (!lstrcmpiW(wszTestFile, wszTestFile2), "GetDisplayNameOf returns incorrect path!\n");
593     }
594     
595     IShellFolder_Release(psfDesktop);
596     IShellFolder_Release(psfPersonal);
597 }
598
599 static void test_CallForAttributes(void)
600 {
601     HKEY hKey;
602     LONG lResult;
603     HRESULT hr;
604     DWORD dwSize;
605     LPSHELLFOLDER psfDesktop;
606     LPITEMIDLIST pidlMyDocuments;
607     DWORD dwAttributes, dwCallForAttributes, dwOrigAttributes, dwOrigCallForAttributes;
608     static const WCHAR wszAttributes[] = { 'A','t','t','r','i','b','u','t','e','s',0 };
609     static const WCHAR wszCallForAttributes[] = { 
610         'C','a','l','l','F','o','r','A','t','t','r','i','b','u','t','e','s',0 };
611     static const WCHAR wszMyDocumentsKey[] = {
612         'C','L','S','I','D','\\','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-',
613         '1','1','D','0','-','9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',
614         '\\','S','h','e','l','l','F','o','l','d','e','r',0 };
615     WCHAR wszMyDocuments[] = {
616         ':',':','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-','1','1','D','0','-',
617         '9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',0 };
618     
619     /* For the root of a namespace extension, the attributes are not queried by binding
620      * to the object and calling GetAttributesOf. Instead, the attributes are read from 
621      * the registry value HKCR/CLSID/{...}/ShellFolder/Attributes. This is documented on MSDN.
622      *
623      * The MyDocuments shellfolder on WinXP has a HKCR/CLSID/{...}/ShellFolder/CallForAttributes
624      * value. It seems that if the folder is queried for one of the flags set in CallForAttributes,
625      * the shell does bind to the folder object and calls GetAttributesOf. This is not documented
626      * on MSDN. This test is meant to document the observed behaviour on WinXP SP2.
627      */
628     hr = SHGetDesktopFolder(&psfDesktop);
629     ok (SUCCEEDED(hr), "SHGetDesktopFolder failed! hr = %08x\n", hr);
630     if (FAILED(hr)) return;
631     
632     hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyDocuments, NULL, 
633                                        &pidlMyDocuments, NULL);
634     ok (SUCCEEDED(hr) ||
635         broken(hr == E_INVALIDARG), /* Win95, NT4 */
636         "Desktop's ParseDisplayName failed to parse MyDocuments's CLSID! hr = %08x\n", hr);
637     if (FAILED(hr)) {
638         IShellFolder_Release(psfDesktop);
639         return;
640     }
641
642     dwAttributes = 0xffffffff;
643     hr = IShellFolder_GetAttributesOf(psfDesktop, 1, 
644                                       (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
645     ok (SUCCEEDED(hr), "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
646
647     /* We need the following setup (as observed on WinXP SP2), for the tests to make sense. */
648     ok (dwAttributes & SFGAO_FILESYSTEM, "SFGAO_FILESYSTEM attribute is not set for MyDocuments!\n");
649     ok (!(dwAttributes & SFGAO_ISSLOW), "SFGAO_ISSLOW attribute is set for MyDocuments!\n");
650     ok (!(dwAttributes & SFGAO_GHOSTED), "SFGAO_GHOSTED attribute is set for MyDocuments!\n");
651
652     /* We don't have the MyDocuments shellfolder in wine yet, and thus we don't have the registry
653      * key. So the test will return at this point, if run on wine. 
654      */
655     lResult = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszMyDocumentsKey, 0, KEY_WRITE|KEY_READ, &hKey);
656     ok (lResult == ERROR_SUCCESS, "RegOpenKeyEx failed! result: %08x\n", lResult);
657     if (lResult != ERROR_SUCCESS) {
658         IMalloc_Free(ppM, pidlMyDocuments);
659         IShellFolder_Release(psfDesktop);
660         return;
661     }
662     
663     /* Query MyDocuments' Attributes value, to be able to restore it later. */
664     dwSize = sizeof(DWORD);
665     lResult = RegQueryValueExW(hKey, wszAttributes, NULL, NULL, (LPBYTE)&dwOrigAttributes, &dwSize);
666     ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
667     if (lResult != ERROR_SUCCESS) {
668         RegCloseKey(hKey);
669         IMalloc_Free(ppM, pidlMyDocuments);
670         IShellFolder_Release(psfDesktop);
671         return;
672     }
673
674     /* Query MyDocuments' CallForAttributes value, to be able to restore it later. */
675     dwSize = sizeof(DWORD);
676     lResult = RegQueryValueExW(hKey, wszCallForAttributes, NULL, NULL, 
677                               (LPBYTE)&dwOrigCallForAttributes, &dwSize);
678     ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
679     if (lResult != ERROR_SUCCESS) {
680         RegCloseKey(hKey);
681         IMalloc_Free(ppM, pidlMyDocuments);
682         IShellFolder_Release(psfDesktop);
683         return;
684     }
685     
686     /* Define via the Attributes value that MyDocuments attributes are SFGAO_ISSLOW and 
687      * SFGAO_GHOSTED and that MyDocuments should be called for the SFGAO_ISSLOW and
688      * SFGAO_FILESYSTEM attributes. */
689     dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED;
690     RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwAttributes, sizeof(DWORD));
691     dwCallForAttributes = SFGAO_ISSLOW|SFGAO_FILESYSTEM;
692     RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD, 
693                    (LPBYTE)&dwCallForAttributes, sizeof(DWORD));
694
695     /* Although it is not set in CallForAttributes, the SFGAO_GHOSTED flag is reset by 
696      * GetAttributesOf. It seems that once there is a single attribute queried, for which
697      * CallForAttributes is set, all flags are taken from the GetAttributesOf call and
698      * the flags in Attributes are ignored. 
699      */
700     dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED|SFGAO_FILESYSTEM;
701     hr = IShellFolder_GetAttributesOf(psfDesktop, 1, 
702                                       (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
703     ok (SUCCEEDED(hr), "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
704     if (SUCCEEDED(hr)) 
705         ok (dwAttributes == SFGAO_FILESYSTEM, 
706             "Desktop->GetAttributes(MyDocuments) returned unexpected attributes: %08x\n", 
707             dwAttributes);
708
709     /* Restore MyDocuments' original Attributes and CallForAttributes registry values */
710     RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwOrigAttributes, sizeof(DWORD));
711     RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD, 
712                    (LPBYTE)&dwOrigCallForAttributes, sizeof(DWORD));
713     RegCloseKey(hKey);
714     IMalloc_Free(ppM, pidlMyDocuments);
715     IShellFolder_Release(psfDesktop);
716 }
717
718 static void test_GetAttributesOf(void) 
719 {
720     HRESULT hr;
721     LPSHELLFOLDER psfDesktop, psfMyComputer;
722     SHITEMID emptyitem = { 0, { 0 } };
723     LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
724     LPITEMIDLIST pidlMyComputer;
725     DWORD dwFlags;
726     static const DWORD desktopFlags[] = {
727         /* WinXP */
728         SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSANCESTOR |
729         SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
730         /* Win2k */
731         SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_STREAM | SFGAO_FILESYSANCESTOR |
732         SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
733         /* WinMe, Win9x, WinNT*/
734         SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSANCESTOR |
735         SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
736     };
737     static const DWORD myComputerFlags[] = {
738         /* WinXP */
739         SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
740         SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
741         /* Win2k */
742         SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_STREAM |
743         SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
744         /* WinMe, Win9x, WinNT */
745         SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
746         SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
747         /* Win95, WinNT when queried directly */
748         SFGAO_CANLINK | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
749         SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
750     };
751     WCHAR wszMyComputer[] = { 
752         ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
753         'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
754     char  cCurrDirA [MAX_PATH] = {0};
755     WCHAR cCurrDirW [MAX_PATH];
756     static WCHAR cTestDirW[] = {'t','e','s','t','d','i','r',0};
757     IShellFolder *IDesktopFolder, *testIShellFolder;
758     ITEMIDLIST *newPIDL;
759     int len, i;
760     BOOL foundFlagsMatch;
761
762     hr = SHGetDesktopFolder(&psfDesktop);
763     ok (SUCCEEDED(hr), "SHGetDesktopFolder failed! hr = %08x\n", hr);
764     if (FAILED(hr)) return;
765
766     /* The Desktop attributes can be queried with a single empty itemidlist, .. */
767     dwFlags = 0xffffffff;
768     hr = IShellFolder_GetAttributesOf(psfDesktop, 1, &pidlEmpty, &dwFlags);
769     ok (SUCCEEDED(hr), "Desktop->GetAttributesOf(empty pidl) failed! hr = %08x\n", hr);
770     for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
771          i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
772     {
773         if (desktopFlags[i] == dwFlags)
774             foundFlagsMatch = TRUE;
775     }
776     ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
777
778     /* .. or with no itemidlist at all. */
779     dwFlags = 0xffffffff;
780     hr = IShellFolder_GetAttributesOf(psfDesktop, 0, NULL, &dwFlags);
781     ok (SUCCEEDED(hr), "Desktop->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
782     for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
783          i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
784     {
785         if (desktopFlags[i] == dwFlags)
786             foundFlagsMatch = TRUE;
787     }
788     ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
789    
790     /* Testing the attributes of the MyComputer shellfolder */
791     hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
792     ok (SUCCEEDED(hr), "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
793     if (FAILED(hr)) {
794         IShellFolder_Release(psfDesktop);
795         return;
796     }
797
798     /* Windows sets the SFGAO_CANLINK flag, when MyComputer is queried via the Desktop
799      * folder object. It doesn't do this, if MyComputer is queried directly (see below).
800      */
801     dwFlags = 0xffffffff;
802     hr = IShellFolder_GetAttributesOf(psfDesktop, 1, (LPCITEMIDLIST*)&pidlMyComputer, &dwFlags);
803     ok (SUCCEEDED(hr), "Desktop->GetAttributesOf(MyComputer) failed! hr = %08x\n", hr);
804     for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
805          i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
806     {
807         if ((myComputerFlags[i] | SFGAO_CANLINK) == dwFlags)
808             foundFlagsMatch = TRUE;
809     }
810     todo_wine
811     ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
812
813     hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
814     ok (SUCCEEDED(hr), "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
815     IShellFolder_Release(psfDesktop);
816     IMalloc_Free(ppM, pidlMyComputer);
817     if (FAILED(hr)) return;
818
819     hr = IShellFolder_GetAttributesOf(psfMyComputer, 1, &pidlEmpty, &dwFlags);
820     todo_wine
821     ok (hr == E_INVALIDARG ||
822         broken(SUCCEEDED(hr)), /* W2K and earlier */
823         "MyComputer->GetAttributesOf(emtpy pidl) should fail! hr = %08x\n", hr);
824
825     dwFlags = 0xffffffff;
826     hr = IShellFolder_GetAttributesOf(psfMyComputer, 0, NULL, &dwFlags);
827     ok (SUCCEEDED(hr), "MyComputer->GetAttributesOf(NULL) failed! hr = %08x\n", hr); 
828     for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
829          i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
830     {
831         if (myComputerFlags[i] == dwFlags)
832             foundFlagsMatch = TRUE;
833     }
834     todo_wine
835     ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
836
837     IShellFolder_Release(psfMyComputer);
838
839     GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
840     len = lstrlenA(cCurrDirA);
841
842     if (len == 0) {
843         win_skip("GetCurrentDirectoryA returned empty string. Skipping test_GetAttributesOf\n");
844         return;
845     }
846     if (len > 3 && cCurrDirA[len-1] == '\\')
847         cCurrDirA[len-1] = 0;
848
849     /* create test directory */
850     CreateFilesFolders();
851
852     MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
853  
854     hr = SHGetDesktopFolder(&IDesktopFolder);
855     ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
856
857     hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
858     ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
859
860     hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
861     ok(hr == S_OK, "BindToObject failed %08x\n", hr);
862
863     IMalloc_Free(ppM, newPIDL);
864
865     /* get relative PIDL */
866     hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
867     ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
868
869     /* test the shell attributes of the test directory using the relative PIDL */
870     dwFlags = SFGAO_FOLDER;
871     hr = IShellFolder_GetAttributesOf(testIShellFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
872     ok (SUCCEEDED(hr), "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
873     ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for relative PIDL: %08x\n", dwFlags);
874
875     /* free memory */
876     IMalloc_Free(ppM, newPIDL);
877
878     /* append testdirectory name to path */
879     if (cCurrDirA[len-1] == '\\')
880         cCurrDirA[len-1] = 0;
881     lstrcatA(cCurrDirA, "\\testdir");
882     MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
883
884     hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
885     ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
886
887     /* test the shell attributes of the test directory using the absolute PIDL */
888     dwFlags = SFGAO_FOLDER;
889     hr = IShellFolder_GetAttributesOf(IDesktopFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
890     ok (SUCCEEDED(hr), "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
891     ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for absolute PIDL: %08x\n", dwFlags);
892
893     /* free memory */
894     IMalloc_Free(ppM, newPIDL);
895
896     IShellFolder_Release(testIShellFolder);
897
898     Cleanup();
899
900     IShellFolder_Release(IDesktopFolder);
901 }
902
903 static void test_SHGetPathFromIDList(void)
904 {
905     SHITEMID emptyitem = { 0, { 0 } };
906     LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
907     LPITEMIDLIST pidlMyComputer;
908     WCHAR wszPath[MAX_PATH], wszDesktop[MAX_PATH];
909     BOOL result;
910     HRESULT hr;
911     LPSHELLFOLDER psfDesktop;
912     WCHAR wszMyComputer[] = { 
913         ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
914         'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
915     WCHAR wszFileName[MAX_PATH];
916     LPITEMIDLIST pidlTestFile;
917     HANDLE hTestFile;
918     STRRET strret;
919     static WCHAR wszTestFile[] = {
920         'w','i','n','e','t','e','s','t','.','f','o','o',0 };
921         HRESULT (WINAPI *pSHGetSpecialFolderLocation)(HWND, int, LPITEMIDLIST *);
922         HMODULE hShell32;
923         LPITEMIDLIST pidlPrograms;
924
925     if(!pSHGetPathFromIDListW || !pSHGetSpecialFolderPathW)
926     {
927         win_skip("SHGetPathFromIDListW() or SHGetSpecialFolderPathW() is missing\n");
928         return;
929     }
930
931     /* Calling SHGetPathFromIDListW with no pidl should return the empty string */
932     wszPath[0] = 'a';
933     wszPath[1] = '\0';
934     result = pSHGetPathFromIDListW(NULL, wszPath);
935     ok(!result, "Expected failure\n");
936     ok(!wszPath[0], "Expected empty string\n");
937
938     /* Calling SHGetPathFromIDListW with an empty pidl should return the desktop folder's path. */
939     result = pSHGetSpecialFolderPathW(NULL, wszDesktop, CSIDL_DESKTOP, FALSE);
940     ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOP) failed! Last error: %u\n", GetLastError());
941     if (!result) return;
942
943     /* Check if we are on Win9x */
944     SetLastError(0xdeadbeef);
945     lstrcmpiW(wszDesktop, wszDesktop);
946     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
947     {
948         win_skip("Most W-calls are not implemented\n");
949         return;
950     }
951
952     result = pSHGetPathFromIDListW(pidlEmpty, wszPath);
953     ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
954     if (!result) return;
955     ok(!lstrcmpiW(wszDesktop, wszPath), "SHGetPathFromIDListW didn't return desktop path for empty pidl!\n");
956
957     /* MyComputer does not map to a filesystem path. SHGetPathFromIDListW should fail. */
958     hr = SHGetDesktopFolder(&psfDesktop);
959     ok (SUCCEEDED(hr), "SHGetDesktopFolder failed! hr = %08x\n", hr);
960     if (FAILED(hr)) return;
961
962     hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
963     ok (SUCCEEDED(hr), "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
964     if (FAILED(hr)) {
965         IShellFolder_Release(psfDesktop);
966         return;
967     }
968
969     SetLastError(0xdeadbeef);
970     wszPath[0] = 'a';
971     wszPath[1] = '\0';
972     result = pSHGetPathFromIDListW(pidlMyComputer, wszPath);
973     ok (!result, "SHGetPathFromIDListW succeeded where it shouldn't!\n");
974     ok (GetLastError()==0xdeadbeef ||
975         GetLastError()==ERROR_SUCCESS, /* Vista and higher */
976         "Unexpected last error from SHGetPathFromIDListW: %u\n", GetLastError());
977     ok (!wszPath[0], "Expected empty path\n");
978     if (result) {
979         IShellFolder_Release(psfDesktop);
980         return;
981     }
982
983     IMalloc_Free(ppM, pidlMyComputer);
984
985     result = pSHGetSpecialFolderPathW(NULL, wszFileName, CSIDL_DESKTOPDIRECTORY, FALSE);
986     ok(result, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
987     if (!result) {
988         IShellFolder_Release(psfDesktop);
989         return;
990     }
991     myPathAddBackslashW(wszFileName);
992     lstrcatW(wszFileName, wszTestFile);
993     hTestFile = CreateFileW(wszFileName, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
994     ok(hTestFile != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: %u\n", GetLastError());
995     if (hTestFile == INVALID_HANDLE_VALUE) {
996         IShellFolder_Release(psfDesktop);
997         return;
998     }
999     CloseHandle(hTestFile);
1000
1001     hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
1002     ok (SUCCEEDED(hr), "Desktop's ParseDisplayName failed to parse filename hr = %08x\n", hr);
1003     if (FAILED(hr)) {
1004         IShellFolder_Release(psfDesktop);
1005         DeleteFileW(wszFileName);
1006         IMalloc_Free(ppM, pidlTestFile);
1007         return;
1008     }
1009
1010     /* This test is to show that the Desktop shellfolder prepends the CSIDL_DESKTOPDIRECTORY
1011      * path for files placed on the desktop, if called with SHGDN_FORPARSING. */
1012     hr = IShellFolder_GetDisplayNameOf(psfDesktop, pidlTestFile, SHGDN_FORPARSING, &strret);
1013     ok (SUCCEEDED(hr), "Desktop's GetDisplayNamfOf failed! hr = %08x\n", hr);
1014     IShellFolder_Release(psfDesktop);
1015     DeleteFileW(wszFileName);
1016     if (FAILED(hr)) {
1017         IMalloc_Free(ppM, pidlTestFile);
1018         return;
1019     }
1020     if (pStrRetToBufW)
1021     {
1022         pStrRetToBufW(&strret, pidlTestFile, wszPath, MAX_PATH);
1023         ok(0 == lstrcmpW(wszFileName, wszPath), 
1024            "Desktop->GetDisplayNameOf(pidlTestFile, SHGDN_FORPARSING) "
1025            "returned incorrect path for file placed on desktop\n");
1026     }
1027
1028     result = pSHGetPathFromIDListW(pidlTestFile, wszPath);
1029     ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1030     IMalloc_Free(ppM, pidlTestFile);
1031     if (!result) return;
1032     ok(0 == lstrcmpW(wszFileName, wszPath), "SHGetPathFromIDListW returned incorrect path for file placed on desktop\n");
1033
1034
1035         /* Test if we can get the path from the start menu "program files" PIDL. */
1036     hShell32 = GetModuleHandleA("shell32");
1037     pSHGetSpecialFolderLocation = (void *)GetProcAddress(hShell32, "SHGetSpecialFolderLocation");
1038
1039     hr = pSHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidlPrograms);
1040     ok(SUCCEEDED(hr), "SHGetFolderLocation failed: 0x%08x\n", hr);
1041
1042     SetLastError(0xdeadbeef);
1043     result = pSHGetPathFromIDListW(pidlPrograms, wszPath);
1044         IMalloc_Free(ppM, pidlPrograms);
1045     ok(result, "SHGetPathFromIDListW failed\n");
1046 }
1047
1048 static void test_EnumObjects_and_CompareIDs(void)
1049 {
1050     ITEMIDLIST *newPIDL;
1051     IShellFolder *IDesktopFolder, *testIShellFolder;
1052     char  cCurrDirA [MAX_PATH] = {0};
1053     static const CHAR cTestDirA[] = "\\testdir";
1054     WCHAR cTestDirW[MAX_PATH];
1055     int len;
1056     HRESULT hr;
1057
1058     GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1059     len = lstrlenA(cCurrDirA);
1060
1061     if(len == 0) {
1062         win_skip("GetCurrentDirectoryA returned empty string. Skipping test_EnumObjects_and_CompareIDs\n");
1063         return;
1064     }
1065     if(cCurrDirA[len-1] == '\\')
1066         cCurrDirA[len-1] = 0;
1067
1068     lstrcatA(cCurrDirA, cTestDirA);
1069     MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cTestDirW, MAX_PATH);
1070
1071     hr = SHGetDesktopFolder(&IDesktopFolder);
1072     ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1073
1074     CreateFilesFolders();
1075
1076     hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1077     ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1078
1079     hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1080     ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1081
1082     test_EnumObjects(testIShellFolder);
1083
1084     IShellFolder_Release(testIShellFolder);
1085
1086     Cleanup();
1087
1088     IMalloc_Free(ppM, newPIDL);
1089
1090     IShellFolder_Release(IDesktopFolder);
1091 }
1092
1093 /* A simple implementation of an IPropertyBag, which returns fixed values for
1094  * 'Target' and 'Attributes' properties.
1095  */
1096 static HRESULT WINAPI InitPropertyBag_IPropertyBag_QueryInterface(IPropertyBag *iface, REFIID riid,
1097     void **ppvObject) 
1098 {
1099     if (!ppvObject)
1100         return E_INVALIDARG;
1101
1102     if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPropertyBag, riid)) {
1103         *ppvObject = iface;
1104     } else {
1105         ok (FALSE, "InitPropertyBag asked for unknown interface!\n");
1106         return E_NOINTERFACE;
1107     }
1108
1109     IPropertyBag_AddRef(iface);
1110     return S_OK;
1111 }
1112
1113 static ULONG WINAPI InitPropertyBag_IPropertyBag_AddRef(IPropertyBag *iface) {
1114     return 2;
1115 }
1116
1117 static ULONG WINAPI InitPropertyBag_IPropertyBag_Release(IPropertyBag *iface) {
1118     return 1;
1119 }
1120
1121 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Read(IPropertyBag *iface, LPCOLESTR pszPropName,
1122     VARIANT *pVar, IErrorLog *pErrorLog)
1123 {
1124     static const WCHAR wszTargetSpecialFolder[] = {
1125         'T','a','r','g','e','t','S','p','e','c','i','a','l','F','o','l','d','e','r',0 };
1126     static const WCHAR wszTarget[] = {
1127         'T','a','r','g','e','t',0 };
1128     static const WCHAR wszAttributes[] = {
1129         'A','t','t','r','i','b','u','t','e','s',0 };
1130     static const WCHAR wszResolveLinkFlags[] = {
1131         'R','e','s','o','l','v','e','L','i','n','k','F','l','a','g','s',0 };
1132     static const WCHAR wszTargetKnownFolder[] = {
1133         'T','a','r','g','e','t','K','n','o','w','n','F','o','l','d','e','r',0 };
1134     static const WCHAR wszCLSID[] = {
1135         'C','L','S','I','D',0 };
1136        
1137     if (!lstrcmpW(pszPropName, wszTargetSpecialFolder)) {
1138         ok(V_VT(pVar) == VT_I4 ||
1139            broken(V_VT(pVar) == VT_BSTR),   /* Win2k */
1140            "Wrong variant type for 'TargetSpecialFolder' property!\n");
1141         return E_INVALIDARG;
1142     }
1143     
1144     if (!lstrcmpW(pszPropName, wszResolveLinkFlags)) 
1145     {
1146         ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'ResolveLinkFlags' property!\n");
1147         return E_INVALIDARG;
1148     }
1149
1150     if (!lstrcmpW(pszPropName, wszTarget)) {
1151         WCHAR wszPath[MAX_PATH];
1152         BOOL result;
1153         
1154         ok(V_VT(pVar) == VT_BSTR ||
1155            broken(V_VT(pVar) == VT_EMPTY),  /* Win2k */
1156            "Wrong variant type for 'Target' property!\n");
1157         if (V_VT(pVar) != VT_BSTR) return E_INVALIDARG;
1158
1159         result = pSHGetSpecialFolderPathW(NULL, wszPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1160         ok(result, "SHGetSpecialFolderPathW(DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1161         if (!result) return E_INVALIDARG;
1162
1163         V_BSTR(pVar) = SysAllocString(wszPath);
1164         return S_OK;
1165     }
1166
1167     if (!lstrcmpW(pszPropName, wszAttributes)) {
1168         ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'Attributes' property!\n");
1169         if (V_VT(pVar) != VT_UI4) return E_INVALIDARG;
1170         V_UI4(pVar) = SFGAO_FOLDER|SFGAO_HASSUBFOLDER|SFGAO_FILESYSANCESTOR|
1171                       SFGAO_CANRENAME|SFGAO_FILESYSTEM;
1172         return S_OK;
1173     }
1174
1175     if (!lstrcmpW(pszPropName, wszTargetKnownFolder)) {
1176         ok(V_VT(pVar) == VT_BSTR, "Wrong variant type for 'TargetKnownFolder' property!\n");
1177         /* TODO */
1178         return E_INVALIDARG;
1179     }
1180
1181     if (!lstrcmpW(pszPropName, wszCLSID)) {
1182         ok(V_VT(pVar) == VT_EMPTY, "Wrong variant type for 'CLSID' property!\n");
1183         /* TODO */
1184         return E_INVALIDARG;
1185     }
1186
1187     ok(FALSE, "PropertyBag was asked for unknown property %s (vt=%d)!\n", wine_dbgstr_w(pszPropName), V_VT(pVar));
1188     return E_INVALIDARG;
1189 }
1190
1191 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Write(IPropertyBag *iface, LPCOLESTR pszPropName,
1192     VARIANT *pVar)
1193 {
1194     ok(FALSE, "Unexpected call to IPropertyBag_Write\n");
1195     return E_NOTIMPL;
1196 }
1197     
1198 static const IPropertyBagVtbl InitPropertyBag_IPropertyBagVtbl = {
1199     InitPropertyBag_IPropertyBag_QueryInterface,
1200     InitPropertyBag_IPropertyBag_AddRef,
1201     InitPropertyBag_IPropertyBag_Release,
1202     InitPropertyBag_IPropertyBag_Read,
1203     InitPropertyBag_IPropertyBag_Write
1204 };
1205
1206 static struct IPropertyBag InitPropertyBag = {
1207     &InitPropertyBag_IPropertyBagVtbl
1208 };
1209
1210 static void test_FolderShortcut(void) {
1211     IPersistPropertyBag *pPersistPropertyBag;
1212     IShellFolder *pShellFolder, *pDesktopFolder;
1213     IPersistFolder3 *pPersistFolder3;
1214     HRESULT hr;
1215     STRRET strret;
1216     WCHAR wszDesktopPath[MAX_PATH], wszBuffer[MAX_PATH];
1217     BOOL result;
1218     CLSID clsid;
1219     LPITEMIDLIST pidlCurrentFolder, pidlWineTestFolder, pidlSubFolder;
1220     HKEY hShellExtKey;
1221     WCHAR wszWineTestFolder[] = {
1222         ':',':','{','9','B','3','5','2','E','B','F','-','2','7','6','5','-','4','5','C','1','-',
1223         'B','4','C','6','-','8','5','C','C','7','F','7','A','B','C','6','4','}',0 };
1224     WCHAR wszShellExtKey[] = { 'S','o','f','t','w','a','r','e','\\',
1225         'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
1226         'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1227         'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
1228         'N','a','m','e','S','p','a','c','e','\\',
1229         '{','9','b','3','5','2','e','b','f','-','2','7','6','5','-','4','5','c','1','-',
1230         'b','4','c','6','-','8','5','c','c','7','f','7','a','b','c','6','4','}',0 };
1231     
1232     WCHAR wszSomeSubFolder[] = { 'S','u','b','F','o','l','d','e','r', 0};
1233     static const GUID CLSID_UnixDosFolder = 
1234         {0x9d20aae8, 0x0625, 0x44b0, {0x9c, 0xa7, 0x71, 0x88, 0x9c, 0x22, 0x54, 0xd9}};
1235
1236     if (!pSHGetSpecialFolderPathW || !pStrRetToBufW) {
1237         win_skip("SHGetSpecialFolderPathW and/or StrRetToBufW are not available\n");
1238         return;
1239     }
1240
1241     if (!pSHGetFolderPathAndSubDirA)
1242     {
1243         win_skip("FolderShortcut test doesn't work on Win2k\n");
1244         return;
1245     }
1246
1247     /* These tests basically show, that CLSID_FolderShortcuts are initialized
1248      * via their IPersistPropertyBag interface. And that the target folder
1249      * is taken from the IPropertyBag's 'Target' property.
1250      */
1251     hr = CoCreateInstance(&CLSID_FolderShortcut, NULL, CLSCTX_INPROC_SERVER, 
1252                           &IID_IPersistPropertyBag, (LPVOID*)&pPersistPropertyBag);
1253     if (hr == REGDB_E_CLASSNOTREG) {
1254         win_skip("CLSID_FolderShortcut is not implemented\n");
1255         return;
1256     }
1257     ok (SUCCEEDED(hr), "CoCreateInstance failed! hr = 0x%08x\n", hr);
1258     if (FAILED(hr)) return;
1259
1260     hr = IPersistPropertyBag_Load(pPersistPropertyBag, &InitPropertyBag, NULL);
1261     ok(SUCCEEDED(hr), "IPersistPropertyBag_Load failed! hr = %08x\n", hr);
1262     if (FAILED(hr)) {
1263         IPersistPropertyBag_Release(pPersistPropertyBag);
1264         return;
1265     }
1266
1267     hr = IPersistPropertyBag_QueryInterface(pPersistPropertyBag, &IID_IShellFolder, 
1268                                             (LPVOID*)&pShellFolder);
1269     IPersistPropertyBag_Release(pPersistPropertyBag);
1270     ok(SUCCEEDED(hr), "IPersistPropertyBag_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1271     if (FAILED(hr)) return;
1272
1273     hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1274     ok(SUCCEEDED(hr), "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1275     if (FAILED(hr)) {
1276         IShellFolder_Release(pShellFolder);
1277         return;
1278     }
1279
1280     result = pSHGetSpecialFolderPathW(NULL, wszDesktopPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1281     ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1282     if (!result) return;
1283
1284     pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1285     ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1286
1287     hr = IShellFolder_QueryInterface(pShellFolder, &IID_IPersistFolder3, (LPVOID*)&pPersistFolder3);
1288     IShellFolder_Release(pShellFolder);
1289     ok(SUCCEEDED(hr), "IShellFolder_QueryInterface(IID_IPersistFolder3 failed! hr = 0x%08x\n", hr);
1290     if (FAILED(hr)) return;
1291
1292     hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1293     ok(SUCCEEDED(hr), "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1294     ok(IsEqualCLSID(&clsid, &CLSID_FolderShortcut), "Unexpected CLSID!\n");
1295
1296     hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1297     ok(SUCCEEDED(hr), "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1298     ok(!pidlCurrentFolder, "IPersistFolder3_GetCurFolder should return a NULL pidl!\n");
1299                     
1300     /* For FolderShortcut objects, the Initialize method initialized the folder's position in the
1301      * shell namespace. The target folder, read from the property bag above, remains untouched. 
1302      * The following tests show this: The itemidlist for some imaginary shellfolder object
1303      * is created and the FolderShortcut is initialized with it. GetCurFolder now returns this
1304      * itemidlist, but GetDisplayNameOf still returns the path from above.
1305      */
1306     hr = SHGetDesktopFolder(&pDesktopFolder);
1307     ok (SUCCEEDED(hr), "SHGetDesktopFolder failed! hr = %08x\n", hr);
1308     if (FAILED(hr)) return;
1309
1310     /* Temporarily register WineTestFolder as a shell namespace extension at the Desktop. 
1311      * Otherwise ParseDisplayName fails on WinXP with E_INVALIDARG */
1312     RegCreateKeyW(HKEY_CURRENT_USER, wszShellExtKey, &hShellExtKey);
1313     RegCloseKey(hShellExtKey);
1314     hr = IShellFolder_ParseDisplayName(pDesktopFolder, NULL, NULL, wszWineTestFolder, NULL,
1315                                        &pidlWineTestFolder, NULL);
1316     RegDeleteKeyW(HKEY_CURRENT_USER, wszShellExtKey);
1317     IShellFolder_Release(pDesktopFolder);
1318     ok (SUCCEEDED(hr), "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1319     if (FAILED(hr)) return;
1320
1321     hr = IPersistFolder3_Initialize(pPersistFolder3, pidlWineTestFolder);
1322     ok (SUCCEEDED(hr), "IPersistFolder3::Initialize failed! hr = %08x\n", hr);
1323     if (FAILED(hr)) {
1324         IPersistFolder3_Release(pPersistFolder3);
1325         pILFree(pidlWineTestFolder);
1326         return;
1327     }
1328
1329     hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1330     ok(SUCCEEDED(hr), "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1331     ok(pILIsEqual(pidlCurrentFolder, pidlWineTestFolder),
1332         "IPersistFolder3_GetCurFolder should return pidlWineTestFolder!\n");
1333     pILFree(pidlCurrentFolder);
1334     pILFree(pidlWineTestFolder);
1335
1336     hr = IPersistFolder3_QueryInterface(pPersistFolder3, &IID_IShellFolder, (LPVOID*)&pShellFolder);
1337     IPersistFolder3_Release(pPersistFolder3);
1338     ok(SUCCEEDED(hr), "IPersistFolder3_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1339     if (FAILED(hr)) return;
1340
1341     hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1342     ok(SUCCEEDED(hr), "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1343     if (FAILED(hr)) {
1344         IShellFolder_Release(pShellFolder);
1345         return;
1346     }
1347
1348     pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1349     ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1350
1351     /* Next few lines are meant to show that children of FolderShortcuts are not FolderShortcuts,
1352      * but ShellFSFolders. */
1353     myPathAddBackslashW(wszDesktopPath);
1354     lstrcatW(wszDesktopPath, wszSomeSubFolder);
1355     if (!CreateDirectoryW(wszDesktopPath, NULL)) {
1356         IShellFolder_Release(pShellFolder);
1357         return;
1358     }
1359     
1360     hr = IShellFolder_ParseDisplayName(pShellFolder, NULL, NULL, wszSomeSubFolder, NULL, 
1361                                        &pidlSubFolder, NULL);
1362     RemoveDirectoryW(wszDesktopPath);
1363     ok (SUCCEEDED(hr), "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1364     if (FAILED(hr)) {
1365         IShellFolder_Release(pShellFolder);
1366         return;
1367     }
1368
1369     hr = IShellFolder_BindToObject(pShellFolder, pidlSubFolder, NULL, &IID_IPersistFolder3,
1370                                    (LPVOID*)&pPersistFolder3);
1371     IShellFolder_Release(pShellFolder);
1372     pILFree(pidlSubFolder);
1373     ok (SUCCEEDED(hr), "IShellFolder::BindToObject failed! hr = %08x\n", hr);
1374     if (FAILED(hr))
1375         return;
1376
1377     /* On windows, we expect CLSID_ShellFSFolder. On wine we relax this constraint
1378      * a little bit and also allow CLSID_UnixDosFolder. */
1379     hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1380     ok(SUCCEEDED(hr), "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1381     ok(IsEqualCLSID(&clsid, &CLSID_ShellFSFolder) || IsEqualCLSID(&clsid, &CLSID_UnixDosFolder),
1382         "IPersistFolder3::GetClassID returned unexpected CLSID!\n");
1383
1384     IPersistFolder3_Release(pPersistFolder3);
1385 }
1386
1387 #include "pshpack1.h"
1388 struct FileStructA {
1389     BYTE  type;
1390     BYTE  dummy;
1391     DWORD dwFileSize;
1392     WORD  uFileDate;    /* In our current implementation this is */
1393     WORD  uFileTime;    /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastWriteTime) */
1394     WORD  uFileAttribs;
1395     CHAR  szName[1];
1396 };
1397
1398 struct FileStructW {
1399     WORD  cbLen;        /* Length of this element. */
1400     BYTE  abFooBar1[6]; /* Beyond any recognition. */
1401     WORD  uDate;        /* FileTimeToDosDate(WIN32_FIND_DATA->ftCreationTime)? */
1402     WORD  uTime;        /* (this is currently speculation) */
1403     WORD  uDate2;       /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastAccessTime)? */
1404     WORD  uTime2;       /* (this is currently speculation) */
1405     BYTE  abFooBar2[4]; /* Beyond any recognition. */
1406     WCHAR wszName[1];   /* The long filename in unicode. */
1407     /* Just for documentation: Right after the unicode string: */
1408     WORD  cbOffset;     /* FileStructW's offset from the beginning of the SHITMEID. 
1409                          * SHITEMID->cb == uOffset + cbLen */
1410 };
1411 #include "poppack.h"
1412
1413 static void test_ITEMIDLIST_format(void) {
1414     WCHAR wszPersonal[MAX_PATH];
1415     LPSHELLFOLDER psfDesktop, psfPersonal;
1416     LPITEMIDLIST pidlPersonal, pidlFile;
1417     HANDLE hFile;
1418     HRESULT hr;
1419     BOOL bResult;
1420     WCHAR wszFile[3][17] = { { 'e','v','e','n','_',0 }, { 'o','d','d','_',0 },
1421         { 'l','o','n','g','e','r','_','t','h','a','n','.','8','_','3',0 } };
1422     int i;
1423
1424     if (!pSHGetSpecialFolderPathW) return;
1425
1426     bResult = pSHGetSpecialFolderPathW(NULL, wszPersonal, CSIDL_PERSONAL, FALSE);
1427     ok(bResult, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1428     if (!bResult) return;
1429
1430     SetLastError(0xdeadbeef);
1431     bResult = SetCurrentDirectoryW(wszPersonal);
1432     if (!bResult && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
1433         win_skip("Most W-calls are not implemented\n");
1434         return;
1435     }
1436     ok(bResult, "SetCurrentDirectory failed! Last error: %u\n", GetLastError());
1437     if (!bResult) return;
1438
1439     hr = SHGetDesktopFolder(&psfDesktop);
1440     ok(SUCCEEDED(hr), "SHGetDesktopFolder failed! hr: %08x\n", hr);
1441     if (FAILED(hr)) return;
1442
1443     hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszPersonal, NULL, &pidlPersonal, NULL);
1444     ok(SUCCEEDED(hr), "psfDesktop->ParseDisplayName failed! hr = %08x\n", hr);
1445     if (FAILED(hr)) {
1446         IShellFolder_Release(psfDesktop);
1447         return;
1448     }
1449
1450     hr = IShellFolder_BindToObject(psfDesktop, pidlPersonal, NULL, &IID_IShellFolder,
1451         (LPVOID*)&psfPersonal);
1452     IShellFolder_Release(psfDesktop);
1453     pILFree(pidlPersonal);
1454     ok(SUCCEEDED(hr), "psfDesktop->BindToObject failed! hr = %08x\n", hr);
1455     if (FAILED(hr)) return;
1456
1457     for (i=0; i<3; i++) {
1458         CHAR szFile[MAX_PATH];
1459         struct FileStructA *pFileStructA;
1460         WORD cbOffset;
1461
1462         WideCharToMultiByte(CP_ACP, 0, wszFile[i], -1, szFile, MAX_PATH, NULL, NULL);
1463
1464         hFile = CreateFileW(wszFile[i], GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_FLAG_WRITE_THROUGH, NULL);
1465         ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed! (%u)\n", GetLastError());
1466         if (hFile == INVALID_HANDLE_VALUE) {
1467             IShellFolder_Release(psfPersonal);
1468             return;
1469         }
1470         CloseHandle(hFile);
1471
1472         hr = IShellFolder_ParseDisplayName(psfPersonal, NULL, NULL, wszFile[i], NULL, &pidlFile, NULL);
1473         DeleteFileW(wszFile[i]);
1474         ok(SUCCEEDED(hr), "psfPersonal->ParseDisplayName failed! hr: %08x\n", hr);
1475         if (FAILED(hr)) {
1476             IShellFolder_Release(psfPersonal);
1477             return;
1478         }
1479
1480         pFileStructA = (struct FileStructA *)pidlFile->mkid.abID;
1481         ok(pFileStructA->type == 0x32, "PIDLTYPE should be 0x32!\n");
1482         ok(pFileStructA->dummy == 0x00, "Dummy Byte should be 0x00!\n");
1483         ok(pFileStructA->dwFileSize == 0, "Filesize should be zero!\n");
1484
1485         if (i < 2) /* First two file names are already in valid 8.3 format */
1486             ok(!strcmp(szFile, (CHAR*)&pidlFile->mkid.abID[12]), "Wrong file name!\n");
1487         else
1488             /* WinXP stores a derived 8.3 dos name (LONGER~1.8_3) here. We probably
1489              * can't implement this correctly, since unix filesystems don't support
1490              * this nasty short/long filename stuff. So we'll probably stay with our
1491              * current habbit of storing the long filename here, which seems to work
1492              * just fine. */
1493             todo_wine
1494             ok(pidlFile->mkid.abID[18] == '~' ||
1495                broken(pidlFile->mkid.abID[34] == '~'),  /* Win2k */
1496                "Should be derived 8.3 name!\n");
1497
1498         if (i == 0) /* First file name has an even number of chars. No need for alignment. */
1499             ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] != '\0' ||
1500                broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1),    /* Win2k */
1501                 "Alignment byte, where there shouldn't be!\n");
1502
1503         if (i == 1) /* Second file name has an uneven number of chars => alignment byte */
1504             ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] == '\0',
1505                 "There should be an alignment byte, but isn't!\n");
1506
1507         /* The offset of the FileStructW member is stored as a WORD at the end of the pidl. */
1508         cbOffset = *(WORD*)(((LPBYTE)pidlFile)+pidlFile->mkid.cb-sizeof(WORD));
1509         ok ((cbOffset >= sizeof(struct FileStructA) &&
1510             cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW)) ||
1511             broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1) ||     /* Win2k on short names */
1512             broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 12 + 1),  /* Win2k on long names */
1513             "Wrong offset value (%d) stored at the end of the PIDL\n", cbOffset);
1514
1515         if (cbOffset >= sizeof(struct FileStructA) &&
1516             cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW))
1517         {
1518             struct FileStructW *pFileStructW = (struct FileStructW *)(((LPBYTE)pidlFile)+cbOffset);
1519
1520             ok(pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen,
1521                 "FileStructW's offset and length should add up to the PIDL's length!\n");
1522
1523             if (pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen) {
1524                 /* Since we just created the file, time of creation,
1525                  * time of last access and time of last write access just be the same.
1526                  * These tests seem to fail sometimes (on WinXP), if the test is run again shortly
1527                  * after the first run. I do remember something with NTFS keeping the creation time
1528                  * if a file is deleted and then created again within a couple of seconds or so.
1529                  * Might be the reason. */
1530                 ok (pFileStructA->uFileDate == pFileStructW->uDate &&
1531                     pFileStructA->uFileTime == pFileStructW->uTime,
1532                     "Last write time should match creation time!\n");
1533
1534                 ok (pFileStructA->uFileDate == pFileStructW->uDate2 &&
1535                     pFileStructA->uFileTime == pFileStructW->uTime2,
1536                     "Last write time should match last access time!\n");
1537
1538                 ok (!lstrcmpW(wszFile[i], pFileStructW->wszName) ||
1539                     !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 22)), /* Vista */
1540                     "The filename should be stored in unicode at this position!\n");
1541             }
1542         }
1543
1544         pILFree(pidlFile);
1545     }
1546 }
1547
1548 static void testSHGetFolderPathAndSubDirA(void)
1549 {
1550     HRESULT ret;
1551     BOOL delret;
1552     DWORD dwret;
1553     int i;
1554     static char wine[] = "wine";
1555     static char winetemp[] = "wine\\temp";
1556     static char appdata[MAX_PATH];
1557     static char testpath[MAX_PATH];
1558     static char toolongpath[MAX_PATH+1];
1559
1560     if(!pSHGetFolderPathA) {
1561         skip("SHGetFolderPathA not present!\n");
1562         return;
1563     }
1564     if(FAILED(pSHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdata)))
1565     {
1566         skip("SHGetFolderPathA failed for CSIDL_LOCAL_APPDATA!\n");
1567         return;
1568     }
1569
1570     sprintf(testpath, "%s\\%s", appdata, winetemp);
1571     delret = RemoveDirectoryA(testpath);
1572     if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) ) {
1573         skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1574         return;
1575     }
1576
1577     sprintf(testpath, "%s\\%s", appdata, wine);
1578     delret = RemoveDirectoryA(testpath);
1579     if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) && (ERROR_FILE_NOT_FOUND != GetLastError())) {
1580         skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1581         return;
1582     }
1583     for(i=0; i< MAX_PATH; i++)
1584         toolongpath[i] = '0' + i % 10;
1585     toolongpath[MAX_PATH] = '\0';
1586
1587     /* test invalid second parameter */
1588     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | 0xff, NULL, SHGFP_TYPE_CURRENT, wine, testpath);
1589     ok(E_INVALIDARG == ret, "expected E_INVALIDARG, got  %x\n", ret);
1590
1591     /* test invalid forth parameter */
1592     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, 2, wine, testpath);
1593     switch(ret) {
1594         case S_OK: /* winvista */
1595             ok(!strncmp(appdata, testpath, strlen(appdata)),
1596                 "expected %s to start with %s\n", testpath, appdata);
1597             ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1598                 "expected %s to end with %s\n", testpath, winetemp);
1599             break;
1600         case E_INVALIDARG: /* winxp, win2k3 */
1601             break;
1602         default:
1603             ok(0, "expected S_OK or E_INVALIDARG, got  %x\n", ret);
1604     }
1605
1606     /* test fifth parameter */
1607     testpath[0] = '\0';
1608     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, NULL, testpath);
1609     ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1610     ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1611
1612     testpath[0] = '\0';
1613     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "", testpath);
1614     ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1615     ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1616
1617     testpath[0] = '\0';
1618     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "\\", testpath);
1619     ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1620     ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1621
1622     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, toolongpath, testpath);
1623     ok(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) == ret,
1624         "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), ret);
1625
1626     testpath[0] = '\0';
1627     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wine, NULL);
1628     ok((S_OK == ret) || (E_INVALIDARG == ret), "expected S_OK or E_INVALIDARG, got %x\n", ret);
1629
1630     /* test a not existing path */
1631     testpath[0] = '\0';
1632     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
1633     ok(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == ret,
1634         "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), ret);
1635
1636     /* create a directory inside a not existing directory */
1637     testpath[0] = '\0';
1638     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_CREATE | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
1639     ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1640     ok(!strncmp(appdata, testpath, strlen(appdata)),
1641         "expected %s to start with %s\n", testpath, appdata);
1642     ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1643         "expected %s to end with %s\n", testpath, winetemp);
1644     dwret = GetFileAttributes(testpath);
1645     ok(FILE_ATTRIBUTE_DIRECTORY | dwret, "expected %x to contain FILE_ATTRIBUTE_DIRECTORY\n", dwret);
1646
1647     /* cleanup */
1648     sprintf(testpath, "%s\\%s", appdata, winetemp);
1649     RemoveDirectoryA(testpath);
1650     sprintf(testpath, "%s\\%s", appdata, wine);
1651     RemoveDirectoryA(testpath);
1652 }
1653
1654 static void test_LocalizedNames(void)
1655 {
1656     static char cCurrDirA[MAX_PATH];
1657     WCHAR cCurrDirW[MAX_PATH], tempbufW[25];
1658     IShellFolder *IDesktopFolder, *testIShellFolder;
1659     ITEMIDLIST *newPIDL;
1660     int len;
1661     HRESULT hr;
1662     static char resourcefile[MAX_PATH];
1663     DWORD res;
1664     HANDLE file;
1665     STRRET strret;
1666
1667     static const char desktopini_contents1[] =
1668         "[.ShellClassInfo]\r\n"
1669         "LocalizedResourceName=@";
1670     static const char desktopini_contents2[] =
1671         ",-1\r\n";
1672     static WCHAR foldernameW[] = {'t','e','s','t','f','o','l','d','e','r',0};
1673     static const WCHAR folderdisplayW[] = {'F','o','l','d','e','r',' ','N','a','m','e',' ','R','e','s','o','u','r','c','e',0};
1674
1675     /* create folder with desktop.ini and localized name in GetModuleFileNameA(NULL) */
1676     CreateDirectoryA(".\\testfolder", NULL);
1677
1678     SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")|FILE_ATTRIBUTE_SYSTEM);
1679
1680     GetModuleFileNameA(NULL, resourcefile, MAX_PATH);
1681
1682     file = CreateFileA(".\\testfolder\\desktop.ini", GENERIC_WRITE, 0, NULL,
1683                          CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1684     ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %i\n", GetLastError());
1685     ok(WriteFile(file, desktopini_contents1, strlen(desktopini_contents1), &res, NULL) &&
1686        WriteFile(file, resourcefile, strlen(resourcefile), &res, NULL) &&
1687        WriteFile(file, desktopini_contents2, strlen(desktopini_contents2), &res, NULL),
1688        "WriteFile failed %i\n", GetLastError());
1689     CloseHandle(file);
1690
1691     /* get IShellFolder for parent */
1692     GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1693     len = lstrlenA(cCurrDirA);
1694
1695     if (len == 0) {
1696         trace("GetCurrentDirectoryA returned empty string. Skipping test_LocalizedNames\n");
1697         goto cleanup;
1698     }
1699     if(cCurrDirA[len-1] == '\\')
1700         cCurrDirA[len-1] = 0;
1701
1702     MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1703
1704     hr = SHGetDesktopFolder(&IDesktopFolder);
1705     ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1706
1707     hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1708     ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1709
1710     hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1711     ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1712
1713     IMalloc_Free(ppM, newPIDL);
1714
1715     /* windows reads the display name from the resource */
1716     hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, foldernameW, NULL, &newPIDL, 0);
1717     ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1718
1719     hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER, &strret);
1720     ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1721
1722     if (SUCCEEDED(hr) && pStrRetToBufW)
1723     {
1724         hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1725         ok (SUCCEEDED(hr), "StrRetToBufW failed! hr = %08x\n", hr);
1726         todo_wine
1727         ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
1728             broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
1729             "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1730     }
1731
1732     /* editing name is also read from the resource */
1733     hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FOREDITING, &strret);
1734     ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1735
1736     if (SUCCEEDED(hr) && pStrRetToBufW)
1737     {
1738         hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1739         ok (SUCCEEDED(hr), "StrRetToBufW failed! hr = %08x\n", hr);
1740         todo_wine
1741         ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
1742             broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
1743             "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1744     }
1745
1746     /* parsing name is unchanged */
1747     hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FORPARSING, &strret);
1748     ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1749
1750     if (SUCCEEDED(hr) && pStrRetToBufW)
1751     {
1752         hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1753         ok (SUCCEEDED(hr), "StrRetToBufW failed! hr = %08x\n", hr);
1754         ok (!lstrcmpiW(tempbufW, foldernameW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1755     }
1756
1757     IShellFolder_Release(IDesktopFolder);
1758     IShellFolder_Release(testIShellFolder);
1759
1760     IMalloc_Free(ppM, newPIDL);
1761
1762 cleanup:
1763     DeleteFileA(".\\testfolder\\desktop.ini");
1764     SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")&~FILE_ATTRIBUTE_SYSTEM);
1765     RemoveDirectoryA(".\\testfolder");
1766 }
1767
1768 static void test_SHCreateShellItem(void)
1769 {
1770     IShellItem *shellitem, *shellitem2;
1771     IPersistIDList *persistidl;
1772     LPITEMIDLIST pidl_cwd=NULL, pidl_testfile, pidl_abstestfile, pidl_test;
1773     HRESULT ret;
1774     char curdirA[MAX_PATH];
1775     WCHAR curdirW[MAX_PATH];
1776     IShellFolder *desktopfolder=NULL, *currentfolder=NULL;
1777     static WCHAR testfileW[] = {'t','e','s','t','f','i','l','e',0};
1778
1779     GetCurrentDirectoryA(MAX_PATH, curdirA);
1780
1781     if (!lstrlenA(curdirA))
1782     {
1783         win_skip("GetCurrentDirectoryA returned empty string, skipping test_SHCreateShellItem\n");
1784         return;
1785     }
1786
1787     MultiByteToWideChar(CP_ACP, 0, curdirA, -1, curdirW, MAX_PATH);
1788
1789     ret = SHGetDesktopFolder(&desktopfolder);
1790     ok(SUCCEEDED(ret), "SHGetShellFolder returned %x\n", ret);
1791
1792     ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
1793     ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
1794
1795     ret = IShellFolder_BindToObject(desktopfolder, pidl_cwd, NULL, &IID_IShellFolder, (void**)&currentfolder);
1796     ok(SUCCEEDED(ret), "BindToObject returned %x\n", ret);
1797
1798     CreateTestFile(".\\testfile");
1799
1800     ret = IShellFolder_ParseDisplayName(currentfolder, NULL, NULL, testfileW, NULL, &pidl_testfile, NULL);
1801     ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
1802
1803     pidl_abstestfile = pILCombine(pidl_cwd, pidl_testfile);
1804
1805     ret = pSHCreateShellItem(NULL, NULL, NULL, &shellitem);
1806     ok(ret == E_INVALIDARG, "SHCreateShellItem returned %x\n", ret);
1807
1808     if (0) /* crashes on Windows XP */
1809     {
1810         pSHCreateShellItem(NULL, NULL, pidl_cwd, NULL);
1811         pSHCreateShellItem(pidl_cwd, NULL, NULL, &shellitem);
1812         pSHCreateShellItem(NULL, currentfolder, NULL, &shellitem);
1813         pSHCreateShellItem(pidl_cwd, currentfolder, NULL, &shellitem);
1814     }
1815
1816     ret = pSHCreateShellItem(NULL, NULL, pidl_cwd, &shellitem);
1817     ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
1818     if (SUCCEEDED(ret))
1819     {
1820         ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
1821         ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1822         if (SUCCEEDED(ret))
1823         {
1824             ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1825             ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1826             if (SUCCEEDED(ret))
1827             {
1828                 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
1829                 pILFree(pidl_test);
1830             }
1831             IPersistIDList_Release(persistidl);
1832         }
1833         IShellItem_Release(shellitem);
1834     }
1835
1836     ret = pSHCreateShellItem(pidl_cwd, NULL, pidl_testfile, &shellitem);
1837     ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
1838     if (SUCCEEDED(ret))
1839     {
1840         ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
1841         ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1842         if (SUCCEEDED(ret))
1843         {
1844             ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1845             ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1846             if (SUCCEEDED(ret))
1847             {
1848                 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
1849                 pILFree(pidl_test);
1850             }
1851             IPersistIDList_Release(persistidl);
1852         }
1853
1854         ret = IShellItem_GetParent(shellitem, &shellitem2);
1855         ok(SUCCEEDED(ret), "GetParent returned %x\n", ret);
1856         if (SUCCEEDED(ret))
1857         {
1858             ret = IShellItem_QueryInterface(shellitem2, &IID_IPersistIDList, (void**)&persistidl);
1859             ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1860             if (SUCCEEDED(ret))
1861             {
1862                 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1863                 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1864                 if (SUCCEEDED(ret))
1865                 {
1866                     ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
1867                     pILFree(pidl_test);
1868                 }
1869                 IPersistIDList_Release(persistidl);
1870             }
1871             IShellItem_Release(shellitem2);
1872         }
1873
1874         IShellItem_Release(shellitem);
1875     }
1876
1877     ret = pSHCreateShellItem(NULL, currentfolder, pidl_testfile, &shellitem);
1878     ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
1879     if (SUCCEEDED(ret))
1880     {
1881         ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
1882         ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1883         if (SUCCEEDED(ret))
1884         {
1885             ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1886             ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1887             if (SUCCEEDED(ret))
1888             {
1889                 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
1890                 pILFree(pidl_test);
1891             }
1892             IPersistIDList_Release(persistidl);
1893         }
1894         IShellItem_Release(shellitem);
1895     }
1896
1897     /* if a parent pidl and shellfolder are specified, the shellfolder is ignored */
1898     ret = pSHCreateShellItem(pidl_cwd, desktopfolder, pidl_testfile, &shellitem);
1899     ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
1900     if (SUCCEEDED(ret))
1901     {
1902         ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
1903         ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1904         if (SUCCEEDED(ret))
1905         {
1906             ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1907             ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1908             if (SUCCEEDED(ret))
1909             {
1910                 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
1911                 pILFree(pidl_test);
1912             }
1913             IPersistIDList_Release(persistidl);
1914         }
1915         IShellItem_Release(shellitem);
1916     }
1917
1918     DeleteFileA(".\\testfile");
1919     pILFree(pidl_abstestfile);
1920     pILFree(pidl_testfile);
1921     pILFree(pidl_cwd);
1922     IShellFolder_Release(currentfolder);
1923     IShellFolder_Release(desktopfolder);
1924 }
1925
1926 START_TEST(shlfolder)
1927 {
1928     init_function_pointers();
1929     /* if OleInitialize doesn't get called, ParseDisplayName returns
1930        CO_E_NOTINITIALIZED for malformed directory names on win2k. */
1931     OleInitialize(NULL);
1932
1933     test_ParseDisplayName();
1934     test_BindToObject();
1935     test_EnumObjects_and_CompareIDs();
1936     test_GetDisplayName();
1937     test_GetAttributesOf();
1938     test_SHGetPathFromIDList();
1939     test_CallForAttributes();
1940     test_FolderShortcut();
1941     test_ITEMIDLIST_format();
1942     if(pSHGetFolderPathAndSubDirA)
1943         testSHGetFolderPathAndSubDirA();
1944     else
1945         skip("SHGetFolderPathAndSubDirA not present\n");
1946     test_LocalizedNames();
1947     if(pSHCreateShellItem)
1948         test_SHCreateShellItem();
1949     else
1950         win_skip("test_SHCreateShellItem not present\n");
1951
1952     OleUninitialize();
1953 }