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