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