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