rsaenh/tests: Fix memory leaks.
[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                 /* On FAT filesystems the last access time is midnight
1529                    local time, so the values of uDate2 and uTime2 will
1530                    depend on the local timezone.  If the times are exactly
1531                    equal then the dates should be identical for both FAT
1532                    and NTFS as no timezone is more than 1 day away from UTC.
1533                 */
1534                 if (pFileStructA->uFileTime == pFileStructW->uTime2)
1535                 {
1536                     ok (pFileStructA->uFileDate == pFileStructW->uDate2,
1537                         "Last write date and time should match last access date and time!\n");
1538                 }
1539                 else
1540                 {
1541                     /* Filesystem may be FAT. Check date within 1 day
1542                        and seconds are zero. */
1543                     trace ("Filesystem may be FAT. Performing less strict atime test.\n");
1544                     ok ((pFileStructW->uTime2 & 0x1F) == 0,
1545                         "Last access time on FAT filesystems should have zero seconds.\n");
1546                     /* TODO: Perform check for date being within one day.*/
1547                 }
1548
1549                 ok (!lstrcmpW(wszFile[i], pFileStructW->wszName) ||
1550                     !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 22)) || /* Vista */
1551                     !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 26)), /* Win7 */
1552                     "The filename should be stored in unicode at this position!\n");
1553             }
1554         }
1555
1556         pILFree(pidlFile);
1557     }
1558 }
1559
1560 static void testSHGetFolderPathAndSubDirA(void)
1561 {
1562     HRESULT ret;
1563     BOOL delret;
1564     DWORD dwret;
1565     int i;
1566     static char wine[] = "wine";
1567     static char winetemp[] = "wine\\temp";
1568     static char appdata[MAX_PATH];
1569     static char testpath[MAX_PATH];
1570     static char toolongpath[MAX_PATH+1];
1571
1572     if(!pSHGetFolderPathA) {
1573         win_skip("SHGetFolderPathA not present!\n");
1574         return;
1575     }
1576     if(FAILED(pSHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdata)))
1577     {
1578         win_skip("SHGetFolderPathA failed for CSIDL_LOCAL_APPDATA!\n");
1579         return;
1580     }
1581
1582     sprintf(testpath, "%s\\%s", appdata, winetemp);
1583     delret = RemoveDirectoryA(testpath);
1584     if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) ) {
1585         win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1586         return;
1587     }
1588
1589     sprintf(testpath, "%s\\%s", appdata, wine);
1590     delret = RemoveDirectoryA(testpath);
1591     if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) && (ERROR_FILE_NOT_FOUND != GetLastError())) {
1592         win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1593         return;
1594     }
1595
1596     /* test invalid second parameter */
1597     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | 0xff, NULL, SHGFP_TYPE_CURRENT, wine, testpath);
1598     ok(E_INVALIDARG == ret, "expected E_INVALIDARG, got  %x\n", ret);
1599
1600     /* test fourth parameter */
1601     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, 2, winetemp, testpath);
1602     switch(ret) {
1603         case S_OK: /* winvista */
1604             ok(!strncmp(appdata, testpath, strlen(appdata)),
1605                 "expected %s to start with %s\n", testpath, appdata);
1606             ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1607                 "expected %s to end with %s\n", testpath, winetemp);
1608             break;
1609         case E_INVALIDARG: /* winxp, win2k3 */
1610             break;
1611         default:
1612             ok(0, "expected S_OK or E_INVALIDARG, got  %x\n", ret);
1613     }
1614
1615     /* test fifth parameter */
1616     testpath[0] = '\0';
1617     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, NULL, testpath);
1618     ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1619     ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1620
1621     testpath[0] = '\0';
1622     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "", testpath);
1623     ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1624     ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1625
1626     testpath[0] = '\0';
1627     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "\\", testpath);
1628     ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1629     ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1630
1631     for(i=0; i< MAX_PATH; i++)
1632         toolongpath[i] = '0' + i % 10;
1633     toolongpath[MAX_PATH] = '\0';
1634     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, toolongpath, testpath);
1635     ok(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) == ret,
1636         "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), ret);
1637
1638     testpath[0] = '\0';
1639     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wine, NULL);
1640     ok((S_OK == ret) || (E_INVALIDARG == ret), "expected S_OK or E_INVALIDARG, got %x\n", ret);
1641
1642     /* test a not existing path */
1643     testpath[0] = '\0';
1644     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
1645     ok(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == ret,
1646         "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), ret);
1647
1648     /* create a directory inside a not existing directory */
1649     testpath[0] = '\0';
1650     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_CREATE | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
1651     ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1652     ok(!strncmp(appdata, testpath, strlen(appdata)),
1653         "expected %s to start with %s\n", testpath, appdata);
1654     ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1655         "expected %s to end with %s\n", testpath, winetemp);
1656     dwret = GetFileAttributes(testpath);
1657     ok(FILE_ATTRIBUTE_DIRECTORY | dwret, "expected %x to contain FILE_ATTRIBUTE_DIRECTORY\n", dwret);
1658
1659     /* cleanup */
1660     sprintf(testpath, "%s\\%s", appdata, winetemp);
1661     RemoveDirectoryA(testpath);
1662     sprintf(testpath, "%s\\%s", appdata, wine);
1663     RemoveDirectoryA(testpath);
1664 }
1665
1666 static void test_LocalizedNames(void)
1667 {
1668     static char cCurrDirA[MAX_PATH];
1669     WCHAR cCurrDirW[MAX_PATH], tempbufW[25];
1670     IShellFolder *IDesktopFolder, *testIShellFolder;
1671     ITEMIDLIST *newPIDL;
1672     int len;
1673     HRESULT hr;
1674     static char resourcefile[MAX_PATH];
1675     DWORD res;
1676     HANDLE file;
1677     STRRET strret;
1678
1679     static const char desktopini_contents1[] =
1680         "[.ShellClassInfo]\r\n"
1681         "LocalizedResourceName=@";
1682     static const char desktopini_contents2[] =
1683         ",-1\r\n";
1684     static WCHAR foldernameW[] = {'t','e','s','t','f','o','l','d','e','r',0};
1685     static const WCHAR folderdisplayW[] = {'F','o','l','d','e','r',' ','N','a','m','e',' ','R','e','s','o','u','r','c','e',0};
1686
1687     /* create folder with desktop.ini and localized name in GetModuleFileNameA(NULL) */
1688     CreateDirectoryA(".\\testfolder", NULL);
1689
1690     SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")|FILE_ATTRIBUTE_SYSTEM);
1691
1692     GetModuleFileNameA(NULL, resourcefile, MAX_PATH);
1693
1694     file = CreateFileA(".\\testfolder\\desktop.ini", GENERIC_WRITE, 0, NULL,
1695                          CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1696     ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %i\n", GetLastError());
1697     ok(WriteFile(file, desktopini_contents1, strlen(desktopini_contents1), &res, NULL) &&
1698        WriteFile(file, resourcefile, strlen(resourcefile), &res, NULL) &&
1699        WriteFile(file, desktopini_contents2, strlen(desktopini_contents2), &res, NULL),
1700        "WriteFile failed %i\n", GetLastError());
1701     CloseHandle(file);
1702
1703     /* get IShellFolder for parent */
1704     GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1705     len = lstrlenA(cCurrDirA);
1706
1707     if (len == 0) {
1708         win_skip("GetCurrentDirectoryA returned empty string. Skipping test_LocalizedNames\n");
1709         goto cleanup;
1710     }
1711     if(cCurrDirA[len-1] == '\\')
1712         cCurrDirA[len-1] = 0;
1713
1714     MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1715
1716     hr = SHGetDesktopFolder(&IDesktopFolder);
1717     ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1718
1719     hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1720     ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1721
1722     hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1723     ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1724
1725     IMalloc_Free(ppM, newPIDL);
1726
1727     /* windows reads the display name from the resource */
1728     hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, foldernameW, NULL, &newPIDL, 0);
1729     ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1730
1731     hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER, &strret);
1732     ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1733
1734     if (SUCCEEDED(hr) && pStrRetToBufW)
1735     {
1736         hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1737         ok (SUCCEEDED(hr), "StrRetToBufW failed! hr = %08x\n", hr);
1738         todo_wine
1739         ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
1740             broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
1741             "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1742     }
1743
1744     /* editing name is also read from the resource */
1745     hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FOREDITING, &strret);
1746     ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1747
1748     if (SUCCEEDED(hr) && pStrRetToBufW)
1749     {
1750         hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1751         ok (SUCCEEDED(hr), "StrRetToBufW failed! hr = %08x\n", hr);
1752         todo_wine
1753         ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
1754             broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
1755             "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1756     }
1757
1758     /* parsing name is unchanged */
1759     hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FORPARSING, &strret);
1760     ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1761
1762     if (SUCCEEDED(hr) && pStrRetToBufW)
1763     {
1764         hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1765         ok (SUCCEEDED(hr), "StrRetToBufW failed! hr = %08x\n", hr);
1766         ok (!lstrcmpiW(tempbufW, foldernameW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1767     }
1768
1769     IShellFolder_Release(IDesktopFolder);
1770     IShellFolder_Release(testIShellFolder);
1771
1772     IMalloc_Free(ppM, newPIDL);
1773
1774 cleanup:
1775     DeleteFileA(".\\testfolder\\desktop.ini");
1776     SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")&~FILE_ATTRIBUTE_SYSTEM);
1777     RemoveDirectoryA(".\\testfolder");
1778 }
1779
1780 static void test_SHCreateShellItem(void)
1781 {
1782     IShellItem *shellitem, *shellitem2;
1783     IPersistIDList *persistidl;
1784     LPITEMIDLIST pidl_cwd=NULL, pidl_testfile, pidl_abstestfile, pidl_test;
1785     HRESULT ret;
1786     char curdirA[MAX_PATH];
1787     WCHAR curdirW[MAX_PATH];
1788     IShellFolder *desktopfolder=NULL, *currentfolder=NULL;
1789     static WCHAR testfileW[] = {'t','e','s','t','f','i','l','e',0};
1790
1791     GetCurrentDirectoryA(MAX_PATH, curdirA);
1792
1793     if (!lstrlenA(curdirA))
1794     {
1795         win_skip("GetCurrentDirectoryA returned empty string, skipping test_SHCreateShellItem\n");
1796         return;
1797     }
1798
1799     MultiByteToWideChar(CP_ACP, 0, curdirA, -1, curdirW, MAX_PATH);
1800
1801     ret = SHGetDesktopFolder(&desktopfolder);
1802     ok(SUCCEEDED(ret), "SHGetShellFolder returned %x\n", ret);
1803
1804     ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
1805     ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
1806
1807     ret = IShellFolder_BindToObject(desktopfolder, pidl_cwd, NULL, &IID_IShellFolder, (void**)&currentfolder);
1808     ok(SUCCEEDED(ret), "BindToObject returned %x\n", ret);
1809
1810     CreateTestFile(".\\testfile");
1811
1812     ret = IShellFolder_ParseDisplayName(currentfolder, NULL, NULL, testfileW, NULL, &pidl_testfile, NULL);
1813     ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
1814
1815     pidl_abstestfile = pILCombine(pidl_cwd, pidl_testfile);
1816
1817     ret = pSHCreateShellItem(NULL, NULL, NULL, &shellitem);
1818     ok(ret == E_INVALIDARG, "SHCreateShellItem returned %x\n", ret);
1819
1820     if (0) /* crashes on Windows XP */
1821     {
1822         pSHCreateShellItem(NULL, NULL, pidl_cwd, NULL);
1823         pSHCreateShellItem(pidl_cwd, NULL, NULL, &shellitem);
1824         pSHCreateShellItem(NULL, currentfolder, NULL, &shellitem);
1825         pSHCreateShellItem(pidl_cwd, currentfolder, NULL, &shellitem);
1826     }
1827
1828     ret = pSHCreateShellItem(NULL, NULL, pidl_cwd, &shellitem);
1829     ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
1830     if (SUCCEEDED(ret))
1831     {
1832         ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
1833         ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1834         if (SUCCEEDED(ret))
1835         {
1836             ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1837             ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1838             if (SUCCEEDED(ret))
1839             {
1840                 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
1841                 pILFree(pidl_test);
1842             }
1843             IPersistIDList_Release(persistidl);
1844         }
1845         IShellItem_Release(shellitem);
1846     }
1847
1848     ret = pSHCreateShellItem(pidl_cwd, NULL, pidl_testfile, &shellitem);
1849     ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
1850     if (SUCCEEDED(ret))
1851     {
1852         ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
1853         ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1854         if (SUCCEEDED(ret))
1855         {
1856             ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1857             ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1858             if (SUCCEEDED(ret))
1859             {
1860                 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
1861                 pILFree(pidl_test);
1862             }
1863             IPersistIDList_Release(persistidl);
1864         }
1865
1866         ret = IShellItem_GetParent(shellitem, &shellitem2);
1867         ok(SUCCEEDED(ret), "GetParent returned %x\n", ret);
1868         if (SUCCEEDED(ret))
1869         {
1870             ret = IShellItem_QueryInterface(shellitem2, &IID_IPersistIDList, (void**)&persistidl);
1871             ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1872             if (SUCCEEDED(ret))
1873             {
1874                 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1875                 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1876                 if (SUCCEEDED(ret))
1877                 {
1878                     ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
1879                     pILFree(pidl_test);
1880                 }
1881                 IPersistIDList_Release(persistidl);
1882             }
1883             IShellItem_Release(shellitem2);
1884         }
1885
1886         IShellItem_Release(shellitem);
1887     }
1888
1889     ret = pSHCreateShellItem(NULL, currentfolder, pidl_testfile, &shellitem);
1890     ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
1891     if (SUCCEEDED(ret))
1892     {
1893         ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
1894         ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1895         if (SUCCEEDED(ret))
1896         {
1897             ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1898             ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1899             if (SUCCEEDED(ret))
1900             {
1901                 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
1902                 pILFree(pidl_test);
1903             }
1904             IPersistIDList_Release(persistidl);
1905         }
1906         IShellItem_Release(shellitem);
1907     }
1908
1909     /* if a parent pidl and shellfolder are specified, the shellfolder is ignored */
1910     ret = pSHCreateShellItem(pidl_cwd, desktopfolder, pidl_testfile, &shellitem);
1911     ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
1912     if (SUCCEEDED(ret))
1913     {
1914         ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
1915         ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1916         if (SUCCEEDED(ret))
1917         {
1918             ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1919             ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1920             if (SUCCEEDED(ret))
1921             {
1922                 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
1923                 pILFree(pidl_test);
1924             }
1925             IPersistIDList_Release(persistidl);
1926         }
1927         IShellItem_Release(shellitem);
1928     }
1929
1930     DeleteFileA(".\\testfile");
1931     pILFree(pidl_abstestfile);
1932     pILFree(pidl_testfile);
1933     pILFree(pidl_cwd);
1934     IShellFolder_Release(currentfolder);
1935     IShellFolder_Release(desktopfolder);
1936 }
1937
1938 START_TEST(shlfolder)
1939 {
1940     init_function_pointers();
1941     /* if OleInitialize doesn't get called, ParseDisplayName returns
1942        CO_E_NOTINITIALIZED for malformed directory names on win2k. */
1943     OleInitialize(NULL);
1944
1945     test_ParseDisplayName();
1946     test_BindToObject();
1947     test_EnumObjects_and_CompareIDs();
1948     test_GetDisplayName();
1949     test_GetAttributesOf();
1950     test_SHGetPathFromIDList();
1951     test_CallForAttributes();
1952     test_FolderShortcut();
1953     test_ITEMIDLIST_format();
1954     if(pSHGetFolderPathAndSubDirA)
1955         testSHGetFolderPathAndSubDirA();
1956     else
1957         win_skip("SHGetFolderPathAndSubDirA not present\n");
1958     test_LocalizedNames();
1959     if(pSHCreateShellItem)
1960         test_SHCreateShellItem();
1961     else
1962         win_skip("SHCreateShellItem not present\n");
1963
1964     OleUninitialize();
1965 }