d3d10core: COM cleanup for the ID3D10Texture3D iface.
[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     BOOL ret;
2065
2066     static const char desktopini_contents1[] =
2067         "[.ShellClassInfo]\r\n"
2068         "LocalizedResourceName=@";
2069     static const char desktopini_contents2[] =
2070         ",-1\r\n";
2071     static WCHAR foldernameW[] = {'t','e','s','t','f','o','l','d','e','r',0};
2072     static const WCHAR folderdisplayW[] = {'F','o','l','d','e','r',' ','N','a','m','e',' ','R','e','s','o','u','r','c','e',0};
2073
2074     /* create folder with desktop.ini and localized name in GetModuleFileNameA(NULL) */
2075     CreateDirectoryA(".\\testfolder", NULL);
2076
2077     SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")|FILE_ATTRIBUTE_SYSTEM);
2078
2079     GetModuleFileNameA(NULL, resourcefile, MAX_PATH);
2080
2081     file = CreateFileA(".\\testfolder\\desktop.ini", GENERIC_WRITE, 0, NULL,
2082                          CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2083     ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %i\n", GetLastError());
2084     ret = WriteFile(file, desktopini_contents1, strlen(desktopini_contents1), &res, NULL) &&
2085           WriteFile(file, resourcefile, strlen(resourcefile), &res, NULL) &&
2086           WriteFile(file, desktopini_contents2, strlen(desktopini_contents2), &res, NULL);
2087     ok(ret, "WriteFile failed %i\n", GetLastError());
2088     CloseHandle(file);
2089
2090     /* get IShellFolder for parent */
2091     GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
2092     len = lstrlenA(cCurrDirA);
2093
2094     if (len == 0) {
2095         win_skip("GetCurrentDirectoryA returned empty string. Skipping test_LocalizedNames\n");
2096         goto cleanup;
2097     }
2098     if(cCurrDirA[len-1] == '\\')
2099         cCurrDirA[len-1] = 0;
2100
2101     MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
2102
2103     hr = SHGetDesktopFolder(&IDesktopFolder);
2104     ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
2105
2106     hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
2107     ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
2108
2109     hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
2110     ok(hr == S_OK, "BindToObject failed %08x\n", hr);
2111
2112     IMalloc_Free(ppM, newPIDL);
2113
2114     /* windows reads the display name from the resource */
2115     hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, foldernameW, NULL, &newPIDL, 0);
2116     ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
2117
2118     hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER, &strret);
2119     ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2120
2121     if (hr == S_OK && pStrRetToBufW)
2122     {
2123         hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2124         ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2125         todo_wine
2126         ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
2127             broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
2128             "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2129     }
2130
2131     /* editing name is also read from the resource */
2132     hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FOREDITING, &strret);
2133     ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2134
2135     if (hr == S_OK && pStrRetToBufW)
2136     {
2137         hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2138         ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2139         todo_wine
2140         ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
2141             broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
2142             "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2143     }
2144
2145     /* parsing name is unchanged */
2146     hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FORPARSING, &strret);
2147     ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2148
2149     if (hr == S_OK && pStrRetToBufW)
2150     {
2151         hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2152         ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2153         ok (!lstrcmpiW(tempbufW, foldernameW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2154     }
2155
2156     IShellFolder_Release(IDesktopFolder);
2157     IShellFolder_Release(testIShellFolder);
2158
2159     IMalloc_Free(ppM, newPIDL);
2160
2161 cleanup:
2162     DeleteFileA(".\\testfolder\\desktop.ini");
2163     SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")&~FILE_ATTRIBUTE_SYSTEM);
2164     RemoveDirectoryA(".\\testfolder");
2165 }
2166
2167 static void test_SHCreateShellItem(void)
2168 {
2169     IShellItem *shellitem, *shellitem2;
2170     IPersistIDList *persistidl;
2171     LPITEMIDLIST pidl_cwd=NULL, pidl_testfile, pidl_abstestfile, pidl_test, pidl_desktop;
2172     HRESULT ret;
2173     char curdirA[MAX_PATH];
2174     WCHAR curdirW[MAX_PATH];
2175     WCHAR fnbufW[MAX_PATH];
2176     IShellFolder *desktopfolder=NULL, *currentfolder=NULL;
2177     static WCHAR testfileW[] = {'t','e','s','t','f','i','l','e',0};
2178
2179     GetCurrentDirectoryA(MAX_PATH, curdirA);
2180
2181     if (!pSHCreateShellItem)
2182     {
2183         win_skip("SHCreateShellItem isn't available\n");
2184         return;
2185     }
2186
2187     if (!lstrlenA(curdirA))
2188     {
2189         win_skip("GetCurrentDirectoryA returned empty string, skipping test_SHCreateShellItem\n");
2190         return;
2191     }
2192
2193     if(pSHGetSpecialFolderLocation)
2194     {
2195         ret = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
2196         ok(ret == S_OK, "Got 0x%08x\n", ret);
2197     }
2198     else
2199     {
2200         win_skip("pSHGetSpecialFolderLocation missing.\n");
2201         pidl_desktop = NULL;
2202     }
2203
2204     MultiByteToWideChar(CP_ACP, 0, curdirA, -1, curdirW, MAX_PATH);
2205
2206     ret = SHGetDesktopFolder(&desktopfolder);
2207     ok(SUCCEEDED(ret), "SHGetShellFolder returned %x\n", ret);
2208
2209     ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2210     ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2211
2212     ret = IShellFolder_BindToObject(desktopfolder, pidl_cwd, NULL, &IID_IShellFolder, (void**)&currentfolder);
2213     ok(SUCCEEDED(ret), "BindToObject returned %x\n", ret);
2214
2215     CreateTestFile(".\\testfile");
2216
2217     ret = IShellFolder_ParseDisplayName(currentfolder, NULL, NULL, testfileW, NULL, &pidl_testfile, NULL);
2218     ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2219
2220     pidl_abstestfile = pILCombine(pidl_cwd, pidl_testfile);
2221
2222     ret = pSHCreateShellItem(NULL, NULL, NULL, &shellitem);
2223     ok(ret == E_INVALIDARG, "SHCreateShellItem returned %x\n", ret);
2224
2225     if (0) /* crashes on Windows XP */
2226     {
2227         pSHCreateShellItem(NULL, NULL, pidl_cwd, NULL);
2228         pSHCreateShellItem(pidl_cwd, NULL, NULL, &shellitem);
2229         pSHCreateShellItem(NULL, currentfolder, NULL, &shellitem);
2230         pSHCreateShellItem(pidl_cwd, currentfolder, NULL, &shellitem);
2231     }
2232
2233     ret = pSHCreateShellItem(NULL, NULL, pidl_cwd, &shellitem);
2234     ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2235     if (SUCCEEDED(ret))
2236     {
2237         ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2238         ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2239         if (SUCCEEDED(ret))
2240         {
2241             ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2242             ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2243             if (SUCCEEDED(ret))
2244             {
2245                 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2246                 pILFree(pidl_test);
2247             }
2248             IPersistIDList_Release(persistidl);
2249         }
2250         IShellItem_Release(shellitem);
2251     }
2252
2253     ret = pSHCreateShellItem(pidl_cwd, NULL, pidl_testfile, &shellitem);
2254     ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2255     if (SUCCEEDED(ret))
2256     {
2257         ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2258         ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2259         if (SUCCEEDED(ret))
2260         {
2261             ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2262             ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2263             if (SUCCEEDED(ret))
2264             {
2265                 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2266                 pILFree(pidl_test);
2267             }
2268             IPersistIDList_Release(persistidl);
2269         }
2270
2271         ret = IShellItem_GetParent(shellitem, &shellitem2);
2272         ok(SUCCEEDED(ret), "GetParent returned %x\n", ret);
2273         if (SUCCEEDED(ret))
2274         {
2275             ret = IShellItem_QueryInterface(shellitem2, &IID_IPersistIDList, (void**)&persistidl);
2276             ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2277             if (SUCCEEDED(ret))
2278             {
2279                 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2280                 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2281                 if (SUCCEEDED(ret))
2282                 {
2283                     ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2284                     pILFree(pidl_test);
2285                 }
2286                 IPersistIDList_Release(persistidl);
2287             }
2288             IShellItem_Release(shellitem2);
2289         }
2290
2291         IShellItem_Release(shellitem);
2292     }
2293
2294     ret = pSHCreateShellItem(NULL, currentfolder, pidl_testfile, &shellitem);
2295     ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2296     if (SUCCEEDED(ret))
2297     {
2298         ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2299         ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2300         if (SUCCEEDED(ret))
2301         {
2302             ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2303             ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2304             if (SUCCEEDED(ret))
2305             {
2306                 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2307                 pILFree(pidl_test);
2308             }
2309             IPersistIDList_Release(persistidl);
2310         }
2311         IShellItem_Release(shellitem);
2312     }
2313
2314     /* if a parent pidl and shellfolder are specified, the shellfolder is ignored */
2315     ret = pSHCreateShellItem(pidl_cwd, desktopfolder, pidl_testfile, &shellitem);
2316     ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2317     if (SUCCEEDED(ret))
2318     {
2319         ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2320         ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2321         if (SUCCEEDED(ret))
2322         {
2323             ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2324             ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2325             if (SUCCEEDED(ret))
2326             {
2327                 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2328                 pILFree(pidl_test);
2329             }
2330             IPersistIDList_Release(persistidl);
2331         }
2332         IShellItem_Release(shellitem);
2333     }
2334
2335     ret = pSHCreateShellItem(NULL, desktopfolder, pidl_testfile, &shellitem);
2336     ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2337     if (SUCCEEDED(ret))
2338     {
2339         ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2340         ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2341         if (SUCCEEDED(ret))
2342         {
2343             ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2344             ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2345             if (SUCCEEDED(ret))
2346             {
2347                 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2348                 pILFree(pidl_test);
2349             }
2350             IPersistIDList_Release(persistidl);
2351         }
2352
2353         IShellItem_Release(shellitem);
2354     }
2355
2356     ret = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
2357     ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2358     if (SUCCEEDED(ret))
2359     {
2360         ret = IShellItem_GetParent(shellitem, &shellitem2);
2361         ok(FAILED(ret), "Got 0x%08x\n", ret);
2362         if(SUCCEEDED(ret)) IShellItem_Release(shellitem2);
2363         IShellItem_Release(shellitem);
2364     }
2365
2366     /* SHCreateItemFromParsingName */
2367     if(pSHCreateItemFromParsingName)
2368     {
2369         if(0)
2370         {
2371             /* Crashes under windows 7 */
2372             pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, NULL);
2373         }
2374
2375         shellitem = (void*)0xdeadbeef;
2376         ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, (void**)&shellitem);
2377         ok(ret == E_INVALIDARG, "SHCreateItemFromParsingName returned %x\n", ret);
2378         ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2379
2380         ret = pSHCreateItemFromParsingName(testfileW, NULL, &IID_IShellItem, (void**)&shellitem);
2381         ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
2382            "SHCreateItemFromParsingName returned %x\n", ret);
2383         if(SUCCEEDED(ret)) IShellItem_Release(shellitem);
2384
2385         lstrcpyW(fnbufW, curdirW);
2386         myPathAddBackslashW(fnbufW);
2387         lstrcatW(fnbufW, testfileW);
2388
2389         ret = pSHCreateItemFromParsingName(fnbufW, NULL, &IID_IShellItem, (void**)&shellitem);
2390         ok(ret == S_OK, "SHCreateItemFromParsingName returned %x\n", ret);
2391         if(SUCCEEDED(ret))
2392         {
2393             LPWSTR tmp_fname;
2394             ret = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &tmp_fname);
2395             ok(ret == S_OK, "GetDisplayName returned %x\n", ret);
2396             if(SUCCEEDED(ret))
2397             {
2398                 ok(!lstrcmpW(fnbufW, tmp_fname), "strings not equal\n");
2399                 CoTaskMemFree(tmp_fname);
2400             }
2401             IShellItem_Release(shellitem);
2402         }
2403     }
2404     else
2405         win_skip("No SHCreateItemFromParsingName\n");
2406
2407
2408     /* SHCreateItemFromIDList */
2409     if(pSHCreateItemFromIDList)
2410     {
2411         if(0)
2412         {
2413             /* Crashes under win7 */
2414             pSHCreateItemFromIDList(NULL, &IID_IShellItem, NULL);
2415         }
2416
2417         ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, (void**)&shellitem);
2418         ok(ret == E_INVALIDARG, "SHCreateItemFromIDList returned %x\n", ret);
2419
2420         ret = pSHCreateItemFromIDList(pidl_cwd, &IID_IShellItem, (void**)&shellitem);
2421         ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2422         if (SUCCEEDED(ret))
2423         {
2424             ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2425             ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2426             if (SUCCEEDED(ret))
2427             {
2428                 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2429                 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2430                 if (SUCCEEDED(ret))
2431                 {
2432                     ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2433                     pILFree(pidl_test);
2434                 }
2435                 IPersistIDList_Release(persistidl);
2436             }
2437             IShellItem_Release(shellitem);
2438         }
2439
2440         ret = pSHCreateItemFromIDList(pidl_testfile, &IID_IShellItem, (void**)&shellitem);
2441         ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2442         if (SUCCEEDED(ret))
2443         {
2444             ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2445             ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2446             if (SUCCEEDED(ret))
2447             {
2448                 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2449                 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2450                 if (SUCCEEDED(ret))
2451                 {
2452                     ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2453                     pILFree(pidl_test);
2454                 }
2455                 IPersistIDList_Release(persistidl);
2456             }
2457             IShellItem_Release(shellitem);
2458         }
2459     }
2460     else
2461         win_skip("No SHCreateItemFromIDList\n");
2462
2463     DeleteFileA(".\\testfile");
2464     pILFree(pidl_abstestfile);
2465     pILFree(pidl_testfile);
2466     pILFree(pidl_desktop);
2467     pILFree(pidl_cwd);
2468     IShellFolder_Release(currentfolder);
2469     IShellFolder_Release(desktopfolder);
2470 }
2471
2472 static void test_SHGetNameFromIDList(void)
2473 {
2474     IShellItem *shellitem;
2475     LPITEMIDLIST pidl;
2476     LPWSTR name_string;
2477     HRESULT hres;
2478     UINT i;
2479     static const DWORD flags[] = {
2480         SIGDN_NORMALDISPLAY, SIGDN_PARENTRELATIVEPARSING,
2481         SIGDN_DESKTOPABSOLUTEPARSING,SIGDN_PARENTRELATIVEEDITING,
2482         SIGDN_DESKTOPABSOLUTEEDITING, /*SIGDN_FILESYSPATH, SIGDN_URL, */
2483         SIGDN_PARENTRELATIVEFORADDRESSBAR,SIGDN_PARENTRELATIVE, -1234};
2484
2485     if(!pSHGetNameFromIDList)
2486     {
2487         win_skip("SHGetNameFromIDList missing.\n");
2488         return;
2489     }
2490
2491     /* These should be available on any platform that passed the above test. */
2492     ok(pSHCreateShellItem != NULL, "SHCreateShellItem missing.\n");
2493     ok(pSHBindToParent != NULL, "SHBindToParent missing.\n");
2494     ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
2495     ok(pStrRetToBufW != NULL, "StrRetToBufW missing.\n");
2496
2497     if(0)
2498     {
2499         /* Crashes under win7 */
2500         pSHGetNameFromIDList(NULL, 0, NULL);
2501     }
2502
2503     hres = pSHGetNameFromIDList(NULL, 0, &name_string);
2504     ok(hres == E_INVALIDARG, "Got 0x%08x\n", hres);
2505
2506     /* Test the desktop */
2507     hres = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
2508     ok(hres == S_OK, "Got 0x%08x\n", hres);
2509     hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2510     ok(hres == S_OK, "Got 0x%08x\n", hres);
2511     if(SUCCEEDED(hres))
2512     {
2513         WCHAR *nameSI, *nameSH;
2514         WCHAR buf[MAX_PATH];
2515         HRESULT hrSI, hrSH, hrSF;
2516         STRRET strret;
2517         IShellFolder *psf;
2518         BOOL res;
2519
2520         SHGetDesktopFolder(&psf);
2521         for(i = 0; flags[i] != -1234; i++)
2522         {
2523             hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2524             ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2525             hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2526             ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2527             hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2528             ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2529
2530             if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2531                 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2532
2533             if(SUCCEEDED(hrSF))
2534             {
2535                 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2536                 if(SUCCEEDED(hrSI))
2537                     ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2538                 if(SUCCEEDED(hrSF))
2539                     ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2540             }
2541             if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2542             if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2543         }
2544         IShellFolder_Release(psf);
2545
2546         if(pSHGetPathFromIDListW){
2547             hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2548             ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2549             res = pSHGetPathFromIDListW(pidl, buf);
2550             ok(res == TRUE, "Got %d\n", res);
2551             if(SUCCEEDED(hrSI) && res)
2552                 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2553             if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2554         }else
2555             win_skip("pSHGetPathFromIDListW not available\n");
2556
2557         hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2558         todo_wine ok(hres == S_OK, "Got 0x%08x\n", hres);
2559         if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2560
2561         IShellItem_Release(shellitem);
2562     }
2563     pILFree(pidl);
2564
2565     /* Test the control panel */
2566     hres = pSHGetSpecialFolderLocation(NULL, CSIDL_CONTROLS, &pidl);
2567     ok(hres == S_OK, "Got 0x%08x\n", hres);
2568     hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2569     ok(hres == S_OK, "Got 0x%08x\n", hres);
2570     if(SUCCEEDED(hres))
2571     {
2572         WCHAR *nameSI, *nameSH;
2573         WCHAR buf[MAX_PATH];
2574         HRESULT hrSI, hrSH, hrSF;
2575         STRRET strret;
2576         IShellFolder *psf;
2577         BOOL res;
2578
2579         SHGetDesktopFolder(&psf);
2580         for(i = 0; flags[i] != -1234; i++)
2581         {
2582             hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2583             ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2584             hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2585             ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2586             hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2587             ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2588
2589             if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2590                 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2591
2592             if(SUCCEEDED(hrSF))
2593             {
2594                 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2595                 if(SUCCEEDED(hrSI))
2596                     ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2597                 if(SUCCEEDED(hrSF))
2598                     ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2599             }
2600             if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2601             if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2602         }
2603         IShellFolder_Release(psf);
2604
2605         if(pSHGetPathFromIDListW){
2606             hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2607             ok(hrSI == E_INVALIDARG, "Got 0x%08x\n", hrSI);
2608             res = pSHGetPathFromIDListW(pidl, buf);
2609             ok(res == FALSE, "Got %d\n", res);
2610             if(SUCCEEDED(hrSI) && res)
2611                 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2612             if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2613         }else
2614             win_skip("pSHGetPathFromIDListW not available\n");
2615
2616         hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2617         todo_wine ok(hres == E_NOTIMPL /* Win7 */ || hres == S_OK /* Vista */,
2618                      "Got 0x%08x\n", hres);
2619         if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2620
2621         IShellItem_Release(shellitem);
2622     }
2623     pILFree(pidl);
2624 }
2625
2626 static void test_SHGetItemFromDataObject(void)
2627 {
2628     IShellFolder *psfdesktop;
2629     IShellItem *psi;
2630     IShellView *psv;
2631     HRESULT hres;
2632
2633     if(!pSHGetItemFromDataObject)
2634     {
2635         win_skip("No SHGetItemFromDataObject.\n");
2636         return;
2637     }
2638
2639     if(0)
2640     {
2641         /* Crashes under win7 */
2642         pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, NULL);
2643     }
2644
2645     hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, (void**)&psv);
2646     ok(hres == E_INVALIDARG, "got 0x%08x\n", hres);
2647
2648     SHGetDesktopFolder(&psfdesktop);
2649
2650     hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
2651     ok(hres == S_OK, "got 0x%08x\n", hres);
2652     if(SUCCEEDED(hres))
2653     {
2654         IEnumIDList *peidl;
2655         IDataObject *pdo;
2656         SHCONTF enum_flags;
2657
2658         enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
2659         hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
2660         ok(hres == S_OK, "got 0x%08x\n", hres);
2661         if(SUCCEEDED(hres))
2662         {
2663             LPITEMIDLIST apidl[5];
2664             UINT count = 0, i;
2665
2666             for(count = 0; count < 5; count++)
2667                 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
2668                     break;
2669
2670             if(count)
2671             {
2672                 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
2673                                                   &IID_IDataObject, NULL, (void**)&pdo);
2674                 ok(hres == S_OK, "got 0x%08x\n", hres);
2675                 if(SUCCEEDED(hres))
2676                 {
2677                     hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2678                     ok(hres == S_OK, "got 0x%08x\n", hres);
2679                     if(SUCCEEDED(hres)) IShellItem_Release(psi);
2680                     hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2681                     ok(hres == S_OK, "got 0x%08x\n", hres);
2682                     if(SUCCEEDED(hres)) IShellItem_Release(psi);
2683                     hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2684                     ok(hres == S_OK, "got 0x%08x\n", hres);
2685                     if(SUCCEEDED(hres)) IShellItem_Release(psi);
2686                     hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2687                     ok(hres == S_OK, "got 0x%08x\n", hres);
2688                     if(SUCCEEDED(hres)) IShellItem_Release(psi);
2689                     hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2690                     ok(hres == S_OK, "got 0x%08x\n", hres);
2691                     if(SUCCEEDED(hres)) IShellItem_Release(psi);
2692
2693                     IDataObject_Release(pdo);
2694                 }
2695             }
2696             else
2697                 skip("No file(s) found - skipping single-file test.\n");
2698
2699             if(count > 1)
2700             {
2701                 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
2702                                                   &IID_IDataObject, NULL, (void**)&pdo);
2703                 ok(hres == S_OK, "got 0x%08x\n", hres);
2704                 if(SUCCEEDED(hres))
2705                 {
2706                     hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2707                     ok(hres == S_OK, "got 0x%08x\n", hres);
2708                     if(SUCCEEDED(hres)) IShellItem_Release(psi);
2709                     hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2710                     ok(hres == S_OK, "got 0x%08x\n", hres);
2711                     if(SUCCEEDED(hres)) IShellItem_Release(psi);
2712                     hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2713                     ok(hres == S_OK, "got 0x%08x\n", hres);
2714                     if(SUCCEEDED(hres)) IShellItem_Release(psi);
2715                     hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2716                     ok(hres == S_OK, "got 0x%08x\n", hres);
2717                     if(SUCCEEDED(hres)) IShellItem_Release(psi);
2718                     hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2719                     ok(hres == E_FAIL, "got 0x%08x\n", hres);
2720                     if(SUCCEEDED(hres)) IShellItem_Release(psi);
2721                     IDataObject_Release(pdo);
2722                 }
2723             }
2724             else
2725                 skip("zero or one file found - skipping multi-file test.\n");
2726
2727             for(i = 0; i < count; i++)
2728                 pILFree(apidl[i]);
2729
2730             IEnumIDList_Release(peidl);
2731         }
2732
2733         IShellView_Release(psv);
2734     }
2735
2736     IShellFolder_Release(psfdesktop);
2737 }
2738
2739 static void test_ShellItemCompare(void)
2740 {
2741     IShellItem *psi[9]; /* a\a, a\b, a\c, b\a, .. */
2742     IShellItem *psi_a = NULL, *psi_b = NULL, *psi_c = NULL;
2743     IShellFolder *psf_desktop, *psf_current;
2744     LPITEMIDLIST pidl_cwd;
2745     WCHAR curdirW[MAX_PATH];
2746     BOOL failed;
2747     HRESULT hr;
2748     static const WCHAR filesW[][9] = {
2749         {'a','\\','a',0}, {'a','\\','b',0}, {'a','\\','c',0},
2750         {'b','\\','a',0}, {'b','\\','b',0}, {'b','\\','c',0},
2751         {'c','\\','a',0}, {'c','\\','b',0}, {'c','\\','c',0} };
2752     int order;
2753     UINT i;
2754
2755     if(!pSHCreateShellItem)
2756     {
2757         win_skip("SHCreateShellItem missing.\n");
2758         return;
2759     }
2760
2761     GetCurrentDirectoryW(MAX_PATH, curdirW);
2762     if(!lstrlenW(curdirW))
2763     {
2764         skip("Failed to get current directory, skipping.\n");
2765         return;
2766     }
2767
2768     CreateDirectoryA(".\\a", NULL);
2769     CreateDirectoryA(".\\b", NULL);
2770     CreateDirectoryA(".\\c", NULL);
2771     CreateTestFile(".\\a\\a");
2772     CreateTestFile(".\\a\\b");
2773     CreateTestFile(".\\a\\c");
2774     CreateTestFile(".\\b\\a");
2775     CreateTestFile(".\\b\\b");
2776     CreateTestFile(".\\b\\c");
2777     CreateTestFile(".\\c\\a");
2778     CreateTestFile(".\\c\\b");
2779     CreateTestFile(".\\c\\c");
2780
2781     SHGetDesktopFolder(&psf_desktop);
2782     hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2783     ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2784     hr = IShellFolder_BindToObject(psf_desktop, pidl_cwd, NULL, &IID_IShellFolder, (void**)&psf_current);
2785     ok(SUCCEEDED(hr), "BindToObject returned %x\n", hr);
2786     IShellFolder_Release(psf_desktop);
2787     ILFree(pidl_cwd);
2788
2789     /* Generate ShellItems for the files */
2790     memset(&psi, 0, sizeof(psi));
2791     failed = FALSE;
2792     for(i = 0; i < 9; i++)
2793     {
2794         LPITEMIDLIST pidl_testfile = NULL;
2795
2796         hr = IShellFolder_ParseDisplayName(psf_current, NULL, NULL, (LPWSTR)filesW[i],
2797                                            NULL, &pidl_testfile, NULL);
2798         ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2799         if(SUCCEEDED(hr))
2800         {
2801             hr = pSHCreateShellItem(NULL, NULL, pidl_testfile, &psi[i]);
2802             ok(hr == S_OK, "Got 0x%08x\n", hr);
2803             pILFree(pidl_testfile);
2804         }
2805         if(FAILED(hr)) failed = TRUE;
2806     }
2807     if(failed)
2808     {
2809         skip("Failed to create all shellitems.\n");
2810         goto cleanup;
2811     }
2812
2813     /* Generate ShellItems for the folders */
2814     hr = IShellItem_GetParent(psi[0], &psi_a);
2815     ok(hr == S_OK, "Got 0x%08x\n", hr);
2816     if(FAILED(hr)) failed = TRUE;
2817     hr = IShellItem_GetParent(psi[3], &psi_b);
2818     ok(hr == S_OK, "Got 0x%08x\n", hr);
2819     if(FAILED(hr)) failed = TRUE;
2820     hr = IShellItem_GetParent(psi[6], &psi_c);
2821     ok(hr == S_OK, "Got 0x%08x\n", hr);
2822     if(FAILED(hr)) failed = TRUE;
2823
2824     if(failed)
2825     {
2826         skip("Failed to create shellitems.\n");
2827         goto cleanup;
2828     }
2829
2830     if(0)
2831     {
2832         /* Crashes on native (win7, winxp) */
2833         IShellItem_Compare(psi_a, NULL, 0, NULL);
2834         IShellItem_Compare(psi_a, psi_b, 0, NULL);
2835         IShellItem_Compare(psi_a, NULL, 0, &order);
2836     }
2837
2838     /* Basics */
2839     for(i = 0; i < 9; i++)
2840     {
2841         hr = IShellItem_Compare(psi[i], psi[i], SICHINT_DISPLAY, &order);
2842         ok(hr == S_OK, "Got 0x%08x\n", hr);
2843         ok(order == 0, "Got order %d\n", order);
2844         hr = IShellItem_Compare(psi[i], psi[i], SICHINT_CANONICAL, &order);
2845         ok(hr == S_OK, "Got 0x%08x\n", hr);
2846         ok(order == 0, "Got order %d\n", order);
2847         hr = IShellItem_Compare(psi[i], psi[i], SICHINT_ALLFIELDS, &order);
2848         ok(hr == S_OK, "Got 0x%08x\n", hr);
2849         ok(order == 0, "Got order %d\n", order);
2850     }
2851
2852     /* Order */
2853     /* a\b:a\a , a\b:a\c, a\b:a\b */
2854     hr = IShellItem_Compare(psi[1], psi[0], SICHINT_DISPLAY, &order);
2855     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2856     ok(order == 1, "Got order %d\n", order);
2857     hr = IShellItem_Compare(psi[1], psi[2], SICHINT_DISPLAY, &order);
2858     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2859     ok(order == -1, "Got order %d\n", order);
2860     hr = IShellItem_Compare(psi[1], psi[1], SICHINT_DISPLAY, &order);
2861     ok(hr == S_OK, "Got 0x%08x\n", hr);
2862     ok(order == 0, "Got order %d\n", order);
2863
2864     /* b\b:a\b, b\b:c\b, b\b:c\b */
2865     hr = IShellItem_Compare(psi[4], psi[1], SICHINT_DISPLAY, &order);
2866     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2867     ok(order == 1, "Got order %d\n", order);
2868     hr = IShellItem_Compare(psi[4], psi[7], SICHINT_DISPLAY, &order);
2869     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2870     ok(order == -1, "Got order %d\n", order);
2871     hr = IShellItem_Compare(psi[4], psi[4], SICHINT_DISPLAY, &order);
2872     ok(hr == S_OK, "Got 0x%08x\n", hr);
2873     ok(order == 0, "Got order %d\n", order);
2874
2875     /* b:a\a, b:a\c, b:a\b */
2876     hr = IShellItem_Compare(psi_b, psi[0], SICHINT_DISPLAY, &order);
2877     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2878     todo_wine ok(order == 1, "Got order %d\n", order);
2879     hr = IShellItem_Compare(psi_b, psi[2], SICHINT_DISPLAY, &order);
2880     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2881     todo_wine ok(order == 1, "Got order %d\n", order);
2882     hr = IShellItem_Compare(psi_b, psi[1], SICHINT_DISPLAY, &order);
2883     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2884     todo_wine ok(order == 1, "Got order %d\n", order);
2885
2886     /* b:c\a, b:c\c, b:c\b */
2887     hr = IShellItem_Compare(psi_b, psi[6], SICHINT_DISPLAY, &order);
2888     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2889     ok(order == -1, "Got order %d\n", order);
2890     hr = IShellItem_Compare(psi_b, psi[8], SICHINT_DISPLAY, &order);
2891     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2892     ok(order == -1, "Got order %d\n", order);
2893     hr = IShellItem_Compare(psi_b, psi[7], SICHINT_DISPLAY, &order);
2894     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2895     ok(order == -1, "Got order %d\n", order);
2896
2897     /* a\b:a\a , a\b:a\c, a\b:a\b */
2898     hr = IShellItem_Compare(psi[1], psi[0], SICHINT_CANONICAL, &order);
2899     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2900     ok(order == 1, "Got order %d\n", order);
2901     hr = IShellItem_Compare(psi[1], psi[2], SICHINT_CANONICAL, &order);
2902     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2903     ok(order == -1, "Got order %d\n", order);
2904     hr = IShellItem_Compare(psi[1], psi[1], SICHINT_CANONICAL, &order);
2905     ok(hr == S_OK, "Got 0x%08x\n", hr);
2906     ok(order == 0, "Got order %d\n", order);
2907
2908     /* b\b:a\b, b\b:c\b, b\b:c\b */
2909     hr = IShellItem_Compare(psi[4], psi[1], SICHINT_CANONICAL, &order);
2910     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2911     ok(order == 1, "Got order %d\n", order);
2912     hr = IShellItem_Compare(psi[4], psi[7], SICHINT_CANONICAL, &order);
2913     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2914     ok(order == -1, "Got order %d\n", order);
2915     hr = IShellItem_Compare(psi[4], psi[4], SICHINT_CANONICAL, &order);
2916     ok(hr == S_OK, "Got 0x%08x\n", hr);
2917     ok(order == 0, "Got order %d\n", order);
2918
2919     /* b:a\a, b:a\c, b:a\b */
2920     hr = IShellItem_Compare(psi_b, psi[0], SICHINT_CANONICAL, &order);
2921     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2922     todo_wine ok(order == 1, "Got order %d\n", order);
2923     hr = IShellItem_Compare(psi_b, psi[2], SICHINT_CANONICAL, &order);
2924     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2925     todo_wine ok(order == 1, "Got order %d\n", order);
2926     hr = IShellItem_Compare(psi_b, psi[1], SICHINT_CANONICAL, &order);
2927     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2928     todo_wine ok(order == 1, "Got order %d\n", order);
2929
2930     /* b:c\a, b:c\c, b:c\b */
2931     hr = IShellItem_Compare(psi_b, psi[6], SICHINT_CANONICAL, &order);
2932     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2933     ok(order == -1, "Got order %d\n", order);
2934     hr = IShellItem_Compare(psi_b, psi[8], SICHINT_CANONICAL, &order);
2935     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2936     ok(order == -1, "Got order %d\n", order);
2937     hr = IShellItem_Compare(psi_b, psi[7], SICHINT_CANONICAL, &order);
2938     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2939     ok(order == -1, "Got order %d\n", order);
2940
2941 cleanup:
2942     IShellFolder_Release(psf_current);
2943
2944     DeleteFileA(".\\a\\a");
2945     DeleteFileA(".\\a\\b");
2946     DeleteFileA(".\\a\\c");
2947     DeleteFileA(".\\b\\a");
2948     DeleteFileA(".\\b\\b");
2949     DeleteFileA(".\\b\\c");
2950     DeleteFileA(".\\c\\a");
2951     DeleteFileA(".\\c\\b");
2952     DeleteFileA(".\\c\\c");
2953     RemoveDirectoryA(".\\a");
2954     RemoveDirectoryA(".\\b");
2955     RemoveDirectoryA(".\\c");
2956
2957     if(psi_a) IShellItem_Release(psi_a);
2958     if(psi_b) IShellItem_Release(psi_b);
2959     if(psi_c) IShellItem_Release(psi_c);
2960
2961     for(i = 0; i < 9; i++)
2962         if(psi[i]) IShellItem_Release(psi[i]);
2963 }
2964
2965 /**************************************************************/
2966 /* IUnknown implementation for counting QueryInterface calls. */
2967 typedef struct {
2968     IUnknown IUnknown_iface;
2969     struct if_count {
2970         REFIID id;
2971         LONG count;
2972     } *ifaces;
2973     LONG unknown;
2974 } IUnknownImpl;
2975
2976 static inline IUnknownImpl *impl_from_IUnknown(IUnknown *iface)
2977 {
2978     return CONTAINING_RECORD(iface, IUnknownImpl, IUnknown_iface);
2979 }
2980
2981 static HRESULT WINAPI unk_fnQueryInterface(IUnknown *iunk, REFIID riid, void** punk)
2982 {
2983     IUnknownImpl *This = impl_from_IUnknown(iunk);
2984     UINT i, found;
2985     for(i = found = 0; This->ifaces[i].id != NULL; i++)
2986     {
2987         if(IsEqualIID(This->ifaces[i].id, riid))
2988         {
2989             This->ifaces[i].count++;
2990             found = 1;
2991             break;
2992         }
2993     }
2994     if(!found)
2995         This->unknown++;
2996     return E_NOINTERFACE;
2997 }
2998
2999 static ULONG WINAPI unk_fnAddRef(IUnknown *iunk)
3000 {
3001     return 2;
3002 }
3003
3004 static ULONG WINAPI unk_fnRelease(IUnknown *iunk)
3005 {
3006     return 1;
3007 }
3008
3009 static const IUnknownVtbl vt_IUnknown = {
3010     unk_fnQueryInterface,
3011     unk_fnAddRef,
3012     unk_fnRelease
3013 };
3014
3015 static void test_SHGetIDListFromObject(void)
3016 {
3017     IUnknownImpl *punkimpl;
3018     IShellFolder *psfdesktop;
3019     IShellView *psv;
3020     LPITEMIDLIST pidl, pidl_desktop;
3021     HRESULT hres;
3022     UINT i;
3023     struct if_count ifaces[] =
3024         { {&IID_IPersistIDList, 0},
3025           {&IID_IPersistFolder2, 0},
3026           {&IID_IDataObject, 0},
3027           {&IID_IParentAndItem, 0},
3028           {&IID_IFolderView, 0},
3029           {NULL, 0} };
3030
3031     if(!pSHGetIDListFromObject)
3032     {
3033         win_skip("SHGetIDListFromObject missing.\n");
3034         return;
3035     }
3036
3037     ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
3038
3039     if(0)
3040     {
3041         /* Crashes native */
3042         pSHGetIDListFromObject(NULL, NULL);
3043         pSHGetIDListFromObject((void*)0xDEADBEEF, NULL);
3044     }
3045
3046     hres = pSHGetIDListFromObject(NULL, &pidl);
3047     ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3048
3049     punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
3050     punkimpl->IUnknown_iface.lpVtbl = &vt_IUnknown;
3051     punkimpl->ifaces = ifaces;
3052     punkimpl->unknown = 0;
3053
3054     hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
3055     ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3056     ok(ifaces[0].count, "interface not requested.\n");
3057     ok(ifaces[1].count, "interface not requested.\n");
3058     ok(ifaces[2].count, "interface not requested.\n");
3059     todo_wine
3060         ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3061            "interface not requested.\n");
3062     ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3063        "interface not requested.\n");
3064
3065     ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3066     HeapFree(GetProcessHeap(), 0, punkimpl);
3067
3068     pidl_desktop = NULL;
3069     pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3070     ok(pidl_desktop != NULL, "Failed to get desktop pidl.\n");
3071
3072     SHGetDesktopFolder(&psfdesktop);
3073
3074     /* Test IShellItem */
3075     if(pSHCreateShellItem)
3076     {
3077         IShellItem *shellitem;
3078         hres = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
3079         ok(hres == S_OK, "got 0x%08x\n", hres);
3080         if(SUCCEEDED(hres))
3081         {
3082             hres = pSHGetIDListFromObject((IUnknown*)shellitem, &pidl);
3083             ok(hres == S_OK, "got 0x%08x\n", hres);
3084             if(SUCCEEDED(hres))
3085             {
3086                 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3087                 pILFree(pidl);
3088             }
3089             IShellItem_Release(shellitem);
3090         }
3091     }
3092     else
3093         skip("no SHCreateShellItem.\n");
3094
3095     /* Test IShellFolder */
3096     hres = pSHGetIDListFromObject((IUnknown*)psfdesktop, &pidl);
3097     ok(hres == S_OK, "got 0x%08x\n", hres);
3098     if(SUCCEEDED(hres))
3099     {
3100         ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3101         pILFree(pidl);
3102     }
3103
3104     hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
3105     ok(hres == S_OK, "got 0x%08x\n", hres);
3106     if(SUCCEEDED(hres))
3107     {
3108         IEnumIDList *peidl;
3109         IDataObject *pdo;
3110         SHCONTF enum_flags;
3111
3112         /* Test IFolderView */
3113         hres = pSHGetIDListFromObject((IUnknown*)psv, &pidl);
3114         ok(hres == S_OK, "got 0x%08x\n", hres);
3115         if(SUCCEEDED(hres))
3116         {
3117             ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3118             pILFree(pidl);
3119         }
3120
3121         /* Test IDataObject */
3122         enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3123         hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
3124         ok(hres == S_OK, "got 0x%08x\n", hres);
3125         if(SUCCEEDED(hres))
3126         {
3127             LPITEMIDLIST apidl[5];
3128             UINT count = 0;
3129             for(count = 0; count < 5; count++)
3130                 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3131                     break;
3132
3133             if(count)
3134             {
3135                 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
3136                                                   &IID_IDataObject, NULL, (void**)&pdo);
3137                 ok(hres == S_OK, "got 0x%08x\n", hres);
3138                 if(SUCCEEDED(hres))
3139                 {
3140                     pidl = (void*)0xDEADBEEF;
3141                     hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3142                     ok(hres == S_OK, "got 0x%08x\n", hres);
3143                     ok(pidl != NULL, "pidl is NULL.\n");
3144                     ok(ILIsEqual(pidl, apidl[0]), "pidl not equal.\n");
3145                     pILFree(pidl);
3146
3147                     IDataObject_Release(pdo);
3148                 }
3149             }
3150             else
3151                 skip("No files found - skipping single-file test.\n");
3152
3153             if(count > 1)
3154             {
3155                 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
3156                                                   &IID_IDataObject, NULL, (void**)&pdo);
3157                 ok(hres == S_OK, "got 0x%08x\n", hres);
3158                 if(SUCCEEDED(hres))
3159                 {
3160                     pidl = (void*)0xDEADBEEF;
3161                     hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3162                     ok(hres == E_NOINTERFACE || hres == E_FAIL /*Vista*/,
3163                        "got 0x%08x\n", hres);
3164                     ok(pidl == NULL, "pidl is not NULL.\n");
3165
3166                     IDataObject_Release(pdo);
3167                 }
3168             }
3169             else
3170                 skip("zero or one file found - skipping multi-file test.\n");
3171
3172             for(i = 0; i < count; i++)
3173                 pILFree(apidl[i]);
3174
3175             IEnumIDList_Release(peidl);
3176         }
3177
3178         IShellView_Release(psv);
3179     }
3180
3181     IShellFolder_Release(psfdesktop);
3182     pILFree(pidl_desktop);
3183 }
3184
3185 static void test_SHGetItemFromObject(void)
3186 {
3187     IUnknownImpl *punkimpl;
3188     IShellFolder *psfdesktop;
3189     LPITEMIDLIST pidl;
3190     IShellItem *psi;
3191     IUnknown *punk;
3192     HRESULT hres;
3193     struct if_count ifaces[] =
3194         { {&IID_IPersistIDList, 0},
3195           {&IID_IPersistFolder2, 0},
3196           {&IID_IDataObject, 0},
3197           {&IID_IParentAndItem, 0},
3198           {&IID_IFolderView, 0},
3199           {NULL, 0} };
3200
3201     if(!pSHGetItemFromObject)
3202     {
3203         skip("No SHGetItemFromObject.\n");
3204         return;
3205     }
3206
3207     SHGetDesktopFolder(&psfdesktop);
3208
3209     if(0)
3210     {
3211         /* Crashes with Windows 7 */
3212         pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IUnknown, NULL);
3213         pSHGetItemFromObject(NULL, &IID_IUnknown, NULL);
3214         pSHGetItemFromObject((IUnknown*)psfdesktop, NULL, (void**)&punk);
3215     }
3216
3217     hres = pSHGetItemFromObject(NULL, &IID_IUnknown, (void**)&punk);
3218     ok(hres == E_NOINTERFACE, "Got 0x%08x\n", hres);
3219
3220     punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
3221     punkimpl->IUnknown_iface.lpVtbl = &vt_IUnknown;
3222     punkimpl->ifaces = ifaces;
3223     punkimpl->unknown = 0;
3224
3225     /* The same as SHGetIDListFromObject */
3226     hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
3227     ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3228     ok(ifaces[0].count, "interface not requested.\n");
3229     ok(ifaces[1].count, "interface not requested.\n");
3230     ok(ifaces[2].count, "interface not requested.\n");
3231     todo_wine
3232         ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3233            "interface not requested.\n");
3234     ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3235        "interface not requested.\n");
3236
3237     ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3238     HeapFree(GetProcessHeap(), 0, punkimpl);
3239
3240     /* Test IShellItem */
3241     hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IShellItem, (void**)&psi);
3242     ok(hres == S_OK, "Got 0x%08x\n", hres);
3243     if(SUCCEEDED(hres))
3244     {
3245         IShellItem *psi2;
3246         hres = pSHGetItemFromObject((IUnknown*)psi, &IID_IShellItem, (void**)&psi2);
3247         ok(hres == S_OK, "Got 0x%08x\n", hres);
3248         if(SUCCEEDED(hres))
3249         {
3250             todo_wine
3251                 ok(psi == psi2, "Different instances (%p != %p).\n", psi, psi2);
3252             IShellItem_Release(psi2);
3253         }
3254         IShellItem_Release(psi);
3255     }
3256
3257     IShellFolder_Release(psfdesktop);
3258 }
3259
3260 static void test_SHCreateShellItemArray(void)
3261 {
3262     IShellFolder *pdesktopsf, *psf;
3263     IShellItemArray *psia;
3264     IEnumIDList *peidl;
3265     HRESULT hr;
3266     WCHAR cTestDirW[MAX_PATH];
3267     LPITEMIDLIST pidl_testdir, pidl;
3268     static const WCHAR testdirW[] = {'t','e','s','t','d','i','r',0};
3269
3270     if(!pSHCreateShellItemArray) {
3271         skip("No pSHCreateShellItemArray!\n");
3272         return;
3273     }
3274
3275     ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
3276
3277     if(0)
3278     {
3279         /* Crashes under native */
3280         pSHCreateShellItemArray(NULL, NULL, 0, NULL, NULL);
3281         pSHCreateShellItemArray(NULL, NULL, 1, NULL, NULL);
3282         pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, NULL);
3283         pSHCreateShellItemArray(pidl, NULL, 0, NULL, NULL);
3284     }
3285
3286     hr = pSHCreateShellItemArray(NULL, NULL, 0, NULL, &psia);
3287     ok(hr == E_POINTER, "got 0x%08x\n", hr);
3288
3289     SHGetDesktopFolder(&pdesktopsf);
3290     hr = pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, &psia);
3291     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3292
3293     hr = pSHCreateShellItemArray(NULL, pdesktopsf, 1, NULL, &psia);
3294     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3295
3296     pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
3297     hr = pSHCreateShellItemArray(pidl, NULL, 0, NULL, &psia);
3298     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3299     pILFree(pidl);
3300
3301     GetCurrentDirectoryW(MAX_PATH, cTestDirW);
3302     myPathAddBackslashW(cTestDirW);
3303     lstrcatW(cTestDirW, testdirW);
3304
3305     CreateFilesFolders();
3306
3307     hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, cTestDirW, NULL, &pidl_testdir, 0);
3308     ok(hr == S_OK, "got 0x%08x\n", hr);
3309     if(SUCCEEDED(hr))
3310     {
3311         hr = IShellFolder_BindToObject(pdesktopsf, pidl_testdir, NULL, (REFIID)&IID_IShellFolder,
3312                                        (void**)&psf);
3313         ok(hr == S_OK, "Got 0x%08x\n", hr);
3314     }
3315     IShellFolder_Release(pdesktopsf);
3316
3317     if(FAILED(hr))
3318     {
3319         skip("Failed to set up environment for SHCreateShellItemArray tests.\n");
3320         pILFree(pidl_testdir);
3321         Cleanup();
3322         return;
3323     }
3324
3325     hr = IShellFolder_EnumObjects(psf, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &peidl);
3326     ok(hr == S_OK, "Got %08x\n", hr);
3327     if(SUCCEEDED(hr))
3328     {
3329         LPITEMIDLIST apidl[5];
3330         UINT done, numitems, i;
3331
3332         for(done = 0; done < 5; done++)
3333             if(IEnumIDList_Next(peidl, 1, &apidl[done], NULL) != S_OK)
3334                 break;
3335         ok(done == 5, "Got %d pidls\n", done);
3336         IEnumIDList_Release(peidl);
3337
3338         /* Create a ShellItemArray */
3339         hr = pSHCreateShellItemArray(NULL, psf, done, (LPCITEMIDLIST*)apidl, &psia);
3340         ok(hr == S_OK, "Got 0x%08x\n", hr);
3341         if(SUCCEEDED(hr))
3342         {
3343             IShellItem *psi;
3344
3345             if(0)
3346             {
3347                 /* Crashes in Windows 7 */
3348                 IShellItemArray_GetCount(psia, NULL);
3349             }
3350
3351             IShellItemArray_GetCount(psia, &numitems);
3352             ok(numitems == done, "Got %d, expected %d\n", numitems, done);
3353
3354             hr = IShellItemArray_GetItemAt(psia, numitems, &psi);
3355             ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3356
3357             /* Compare all the items */
3358             for(i = 0; i < numitems; i++)
3359             {
3360                 LPITEMIDLIST pidl_abs;
3361                 pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3362
3363                 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3364                 ok(hr == S_OK, "(%d) Failed with 0x%08x\n", i, hr);
3365                 if(SUCCEEDED(hr))
3366                 {
3367                     hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3368                     ok(hr == S_OK, "Got 0x%08x\n", hr);
3369                     if(SUCCEEDED(hr))
3370                     {
3371                         ok(ILIsEqual(pidl_abs, pidl), "Pidl not equal.\n");
3372                         pILFree(pidl);
3373                     }
3374                     IShellItem_Release(psi);
3375                 }
3376                 pILFree(pidl_abs);
3377             }
3378             for(i = 0; i < done; i++)
3379                 pILFree(apidl[i]);
3380             IShellItemArray_Release(psia);
3381         }
3382     }
3383
3384     /* SHCreateShellItemArrayFromShellItem */
3385     if(pSHCreateShellItemArrayFromShellItem)
3386     {
3387         IShellItem *psi;
3388
3389         if(0)
3390         {
3391             /* Crashes under Windows 7 */
3392             pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, NULL);
3393             pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, (void**)&psia);
3394             pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, NULL);
3395         }
3396
3397         hr = pSHCreateItemFromIDList(pidl_testdir, &IID_IShellItem, (void**)&psi);
3398         ok(hr == S_OK, "Got 0x%08x\n", hr);
3399         if(SUCCEEDED(hr))
3400         {
3401             hr = pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, (void**)&psia);
3402             ok(hr == S_OK, "Got 0x%08x\n", hr);
3403             if(SUCCEEDED(hr))
3404             {
3405                 IShellItem *psi2;
3406                 UINT count;
3407                 hr = IShellItemArray_GetCount(psia, &count);
3408                 ok(hr == S_OK, "Got 0x%08x\n", hr);
3409                 ok(count == 1, "Got count %d\n", count);
3410                 hr = IShellItemArray_GetItemAt(psia, 0, &psi2);
3411                 ok(hr == S_OK, "Got 0x%08x\n", hr);
3412                 todo_wine
3413                     ok(psi != psi2, "ShellItems are of the same instance.\n");
3414                 if(SUCCEEDED(hr))
3415                 {
3416                     LPITEMIDLIST pidl1, pidl2;
3417                     hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl1);
3418                     ok(hr == S_OK, "Got 0x%08x\n", hr);
3419                     ok(pidl1 != NULL, "pidl1 was null.\n");
3420                     hr = pSHGetIDListFromObject((IUnknown*)psi2, &pidl2);
3421                     ok(hr == S_OK, "Got 0x%08x\n", hr);
3422                     ok(pidl2 != NULL, "pidl2 was null.\n");
3423                     ok(ILIsEqual(pidl1, pidl2), "pidls not equal.\n");
3424                     pILFree(pidl1);
3425                     pILFree(pidl2);
3426                     IShellItem_Release(psi2);
3427                 }
3428                 hr = IShellItemArray_GetItemAt(psia, 1, &psi2);
3429                 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3430                 IShellItemArray_Release(psia);
3431             }
3432             IShellItem_Release(psi);
3433         }
3434     }
3435     else
3436         skip("No SHCreateShellItemArrayFromShellItem.\n");
3437
3438     if(pSHCreateShellItemArrayFromDataObject)
3439     {
3440         IShellView *psv;
3441
3442         if(0)
3443         {
3444             /* Crashes under Windows 7 */
3445             pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, NULL);
3446         }
3447         hr = pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, (void**)&psia);
3448         ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3449
3450         hr = IShellFolder_CreateViewObject(psf, NULL, &IID_IShellView, (void**)&psv);
3451         ok(hr == S_OK, "got 0x%08x\n", hr);
3452         if(SUCCEEDED(hr))
3453         {
3454             IEnumIDList *peidl;
3455             IDataObject *pdo;
3456             SHCONTF enum_flags;
3457
3458             enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3459             hr = IShellFolder_EnumObjects(psf, NULL, enum_flags, &peidl);
3460             ok(hr == S_OK, "got 0x%08x\n", hr);
3461             if(SUCCEEDED(hr))
3462             {
3463                 LPITEMIDLIST apidl[5];
3464                 UINT count, i;
3465
3466                 for(count = 0; count < 5; count++)
3467                     if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3468                         break;
3469                 ok(count == 5, "Got %d\n", count);
3470
3471                 if(count)
3472                 {
3473                     hr = IShellFolder_GetUIObjectOf(psf, NULL, count, (LPCITEMIDLIST*)apidl,
3474                                                     &IID_IDataObject, NULL, (void**)&pdo);
3475                     ok(hr == S_OK, "Got 0x%08x\n", hr);
3476                     if(SUCCEEDED(hr))
3477                     {
3478                         hr = pSHCreateShellItemArrayFromDataObject(pdo, &IID_IShellItemArray,
3479                                                                    (void**)&psia);
3480                         ok(hr == S_OK, "Got 0x%08x\n", hr);
3481                         if(SUCCEEDED(hr))
3482                         {
3483                             UINT count_sia, i;
3484                             hr = IShellItemArray_GetCount(psia, &count_sia);
3485                             ok(hr == S_OK, "Got 0x%08x\n", hr);
3486                             ok(count_sia == count, "Counts differ (%d, %d)\n", count, count_sia);
3487                             for(i = 0; i < count_sia; i++)
3488                             {
3489                                 LPITEMIDLIST pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3490                                 IShellItem *psi;
3491                                 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3492                                 ok(hr == S_OK, "Got 0x%08x\n", hr);
3493                                 if(SUCCEEDED(hr))
3494                                 {
3495                                     LPITEMIDLIST pidl;
3496                                     hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3497                                     ok(hr == S_OK, "Got 0x%08x\n", hr);
3498                                     ok(pidl != NULL, "pidl as NULL.\n");
3499                                     ok(ILIsEqual(pidl, pidl_abs), "pidls differ.\n");
3500                                     pILFree(pidl);
3501                                     IShellItem_Release(psi);
3502                                 }
3503                                 pILFree(pidl_abs);
3504                             }
3505
3506                             IShellItemArray_Release(psia);
3507                         }
3508
3509                         IDataObject_Release(pdo);
3510                     }
3511                     for(i = 0; i < count; i++)
3512                         pILFree(apidl[i]);
3513                 }
3514                 else
3515                     skip("No files found - skipping test.\n");
3516
3517                 IEnumIDList_Release(peidl);
3518             }
3519             IShellView_Release(psv);
3520         }
3521     }
3522     else
3523         skip("No SHCreateShellItemArrayFromDataObject.\n");
3524
3525     IShellFolder_Release(psf);
3526     pILFree(pidl_testdir);
3527     Cleanup();
3528 }
3529
3530 static void test_ShellItemBindToHandler(void)
3531 {
3532     IShellItem *psi;
3533     LPITEMIDLIST pidl_desktop;
3534     HRESULT hr;
3535
3536     if(!pSHCreateShellItem)
3537     {
3538         skip("SHCreateShellItem missing.\n");
3539         return;
3540     }
3541
3542     hr = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3543     ok(hr == S_OK, "Got 0x%08x\n", hr);
3544     if(SUCCEEDED(hr))
3545     {
3546         hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
3547         ok(hr == S_OK, "Got 0x%08x\n", hr);
3548     }
3549     if(SUCCEEDED(hr))
3550     {
3551         IPersistFolder2 *ppf2;
3552         IUnknown *punk;
3553
3554         if(0)
3555         {
3556             /* Crashes under Windows 7 */
3557             IShellItem_BindToHandler(psi, NULL, NULL, NULL, NULL);
3558             IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, NULL);
3559         }
3560         hr = IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, (void**)&punk);
3561         ok(hr == MK_E_NOOBJECT, "Got 0x%08x\n", hr);
3562
3563         /* BHID_SFObject */
3564         hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IShellFolder, (void**)&punk);
3565         ok(hr == S_OK, "Got 0x%08x\n", hr);
3566         if(SUCCEEDED(hr)) IUnknown_Release(punk);
3567         hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IPersistFolder2, (void**)&ppf2);
3568         ok(hr == S_OK, "Got 0x%08x\n", hr);
3569         if(SUCCEEDED(hr))
3570         {
3571             LPITEMIDLIST pidl_tmp;
3572             hr = IPersistFolder2_GetCurFolder(ppf2, &pidl_tmp);
3573             ok(hr == S_OK, "Got 0x%08x\n", hr);
3574             if(SUCCEEDED(hr))
3575             {
3576                 ok(ILIsEqual(pidl_desktop, pidl_tmp), "Pidl not equal (%p, %p)\n", pidl_desktop, pidl_tmp);
3577                 pILFree(pidl_tmp);
3578             }
3579             IPersistFolder2_Release(ppf2);
3580         }
3581
3582         /* BHID_SFUIObject */
3583         hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IDataObject, (void**)&punk);
3584         ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3585         if(SUCCEEDED(hr)) IUnknown_Release(punk);
3586         hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IContextMenu, (void**)&punk);
3587         ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3588         if(SUCCEEDED(hr)) IUnknown_Release(punk);
3589
3590         /* BHID_DataObject */
3591         hr = IShellItem_BindToHandler(psi, NULL, &BHID_DataObject, &IID_IDataObject, (void**)&punk);
3592         ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3593         if(SUCCEEDED(hr)) IUnknown_Release(punk);
3594
3595         todo_wine
3596         {
3597             /* BHID_SFViewObject */
3598             hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellView, (void**)&punk);
3599             ok(hr == S_OK, "Got 0x%08x\n", hr);
3600             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3601             hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellFolderView, (void**)&punk);
3602             ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3603             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3604
3605             /* BHID_Storage */
3606             hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &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_Storage, &IID_IUnknown, (void**)&punk);
3610             ok(hr == S_OK, "Got 0x%08x\n", hr);
3611             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3612
3613             /* BHID_Stream */
3614             hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IStream, (void**)&punk);
3615             ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3616             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3617             hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IUnknown, (void**)&punk);
3618             ok(hr == S_OK, "Got 0x%08x\n", hr);
3619             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3620
3621             /* BHID_StorageEnum */
3622             hr = IShellItem_BindToHandler(psi, NULL, &BHID_StorageEnum, &IID_IEnumShellItems, (void**)&punk);
3623             ok(hr == S_OK, "Got 0x%08x\n", hr);
3624             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3625
3626             /* BHID_Transfer */
3627             hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_IUnknown, (void**)&punk);
3628             ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3629             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3630
3631             /* BHID_EnumItems */
3632             hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumItems, &IID_IEnumShellItems, (void**)&punk);
3633             ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3634             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3635
3636             /* BHID_Filter */
3637             hr = IShellItem_BindToHandler(psi, NULL, &BHID_Filter, &IID_IUnknown, (void**)&punk);
3638             ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3639             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3640
3641             /* BHID_LinkTargetItem */
3642             hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IShellItem, (void**)&punk);
3643             ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3644             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3645             hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IUnknown, (void**)&punk);
3646             ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3647             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3648
3649             /* BHID_PropertyStore */
3650             hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStore, (void**)&punk);
3651             ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3652             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3653             hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStoreFactory, (void**)&punk);
3654             ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3655             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3656
3657             /* BHID_ThumbnailHandler */
3658             hr = IShellItem_BindToHandler(psi, NULL, &BHID_ThumbnailHandler, &IID_IUnknown, (void**)&punk);
3659             ok(hr == E_INVALIDARG || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3660             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3661
3662             /* BHID_AssociationArray */
3663             hr = IShellItem_BindToHandler(psi, NULL, &BHID_AssociationArray, &IID_IQueryAssociations, (void**)&punk);
3664             ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3665             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3666
3667             /* BHID_EnumAssocHandlers */
3668             hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumAssocHandlers, &IID_IUnknown, (void**)&punk);
3669             ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3670             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3671         }
3672
3673         IShellItem_Release(psi);
3674     }
3675     else
3676         skip("Failed to create ShellItem.\n");
3677
3678     pILFree(pidl_desktop);
3679 }
3680
3681 static void test_ShellItemGetAttributes(void)
3682 {
3683     IShellItem *psi;
3684     LPITEMIDLIST pidl_desktop;
3685     SFGAOF sfgao;
3686     HRESULT hr;
3687
3688     if(!pSHCreateShellItem)
3689     {
3690         skip("SHCreateShellItem missing.\n");
3691         return;
3692     }
3693
3694     hr = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3695     ok(hr == S_OK, "Got 0x%08x\n", hr);
3696     if(SUCCEEDED(hr))
3697     {
3698         hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
3699         ok(hr == S_OK, "Got 0x%08x\n", hr);
3700         pILFree(pidl_desktop);
3701     }
3702     if(FAILED(hr))
3703     {
3704         skip("Skipping tests.\n");
3705         return;
3706     }
3707
3708     if(0)
3709     {
3710         /* Crashes on native (Win 7) */
3711         IShellItem_GetAttributes(psi, 0, NULL);
3712     }
3713
3714     /* Test GetAttributes on the desktop folder. */
3715     sfgao = 0xdeadbeef;
3716     hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER, &sfgao);
3717     ok(hr == S_OK || broken(hr == E_FAIL) /* <Vista */, "Got 0x%08x\n", hr);
3718     ok(sfgao == SFGAO_FOLDER || broken(sfgao == 0) /* <Vista */, "Got 0x%08x\n", sfgao);
3719
3720     IShellItem_Release(psi);
3721 }
3722
3723 static void test_SHParseDisplayName(void)
3724 {
3725     LPITEMIDLIST pidl1, pidl2;
3726     IShellFolder *desktop;
3727     WCHAR dirW[MAX_PATH];
3728     WCHAR nameW[10];
3729     HRESULT hr;
3730     BOOL ret;
3731
3732     if (!pSHParseDisplayName)
3733     {
3734         win_skip("SHParseDisplayName isn't available\n");
3735         return;
3736     }
3737
3738 if (0)
3739 {
3740     /* crashes on native */
3741     pSHParseDisplayName(NULL, NULL, NULL, 0, NULL);
3742     nameW[0] = 0;
3743     pSHParseDisplayName(nameW, NULL, NULL, 0, NULL);
3744 }
3745
3746     pidl1 = (LPITEMIDLIST)0xdeadbeef;
3747     hr = pSHParseDisplayName(NULL, NULL, &pidl1, 0, NULL);
3748     ok(broken(hr == E_OUTOFMEMORY) /* < Vista */ ||
3749        hr == E_INVALIDARG, "failed %08x\n", hr);
3750     ok(pidl1 == 0, "expected null ptr, got %p\n", pidl1);
3751
3752     /* dummy name */
3753     nameW[0] = 0;
3754     hr = pSHParseDisplayName(nameW, NULL, &pidl1, 0, NULL);
3755     ok(hr == S_OK, "failed %08x\n", hr);
3756     hr = SHGetDesktopFolder(&desktop);
3757     ok(hr == S_OK, "failed %08x\n", hr);
3758     hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, nameW, NULL, &pidl2, NULL);
3759     ok(hr == S_OK, "failed %08x\n", hr);
3760     ret = pILIsEqual(pidl1, pidl2);
3761     ok(ret == TRUE, "expected equal idls\n");
3762     pILFree(pidl1);
3763     pILFree(pidl2);
3764
3765     /* with path */
3766     GetWindowsDirectoryW( dirW, MAX_PATH );
3767
3768     hr = pSHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
3769     ok(hr == S_OK, "failed %08x\n", hr);
3770     hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, dirW, NULL, &pidl2, NULL);
3771     ok(hr == S_OK, "failed %08x\n", hr);
3772
3773     ret = pILIsEqual(pidl1, pidl2);
3774     ok(ret == TRUE, "expected equal idls\n");
3775     pILFree(pidl1);
3776     pILFree(pidl2);
3777
3778     IShellFolder_Release(desktop);
3779 }
3780
3781 static void test_desktop_IPersist(void)
3782 {
3783     IShellFolder *desktop;
3784     IPersist *persist;
3785     IPersistFolder2 *ppf2;
3786     CLSID clsid;
3787     HRESULT hr;
3788
3789     hr = SHGetDesktopFolder(&desktop);
3790     ok(hr == S_OK, "failed %08x\n", hr);
3791
3792     hr = IShellFolder_QueryInterface(desktop, &IID_IPersist, (void**)&persist);
3793     ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* NT4, W9X */, "failed %08x\n", hr);
3794
3795     if (hr == S_OK)
3796     {
3797     if (0)
3798     {
3799         /* crashes on native */
3800         IPersist_GetClassID(persist, NULL);
3801     }
3802         memset(&clsid, 0, sizeof(clsid));
3803         hr = IPersist_GetClassID(persist, &clsid);
3804         ok(hr == S_OK, "failed %08x\n", hr);
3805         ok(IsEqualIID(&CLSID_ShellDesktop, &clsid), "Expected CLSID_ShellDesktop\n");
3806         IPersist_Release(persist);
3807     }
3808
3809     hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder2, (void**)&ppf2);
3810     ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* pre-Vista */, "failed %08x\n", hr);
3811     if(SUCCEEDED(hr))
3812     {
3813         IPersistFolder *ppf;
3814         LPITEMIDLIST pidl;
3815         hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder, (void**)&ppf);
3816         ok(hr == S_OK, "IID_IPersistFolder2 without IID_IPersistFolder.\n");
3817         if(SUCCEEDED(hr))
3818             IPersistFolder_Release(ppf);
3819
3820         todo_wine {
3821             hr = IPersistFolder2_Initialize(ppf2, NULL);
3822             ok(hr == S_OK, "got %08x\n", hr);
3823         }
3824
3825         pidl = NULL;
3826         hr = IPersistFolder2_GetCurFolder(ppf2, &pidl);
3827         ok(hr == S_OK, "got %08x\n", hr);
3828         ok(pidl != NULL, "pidl was NULL.\n");
3829         if(SUCCEEDED(hr)) pILFree(pidl);
3830
3831         IPersistFolder2_Release(ppf2);
3832     }
3833
3834     IShellFolder_Release(desktop);
3835 }
3836
3837 static void test_GetUIObject(void)
3838 {
3839     IShellFolder *psf_desktop;
3840     IContextMenu *pcm;
3841     LPITEMIDLIST pidl;
3842     HRESULT hr;
3843     WCHAR path[MAX_PATH];
3844     const WCHAR filename[] =
3845         {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
3846
3847     if(!pSHBindToParent)
3848     {
3849         win_skip("SHBindToParent missing.\n");
3850         return;
3851     }
3852
3853     GetCurrentDirectoryW(MAX_PATH, path);
3854     if(!lstrlenW(path))
3855     {
3856         skip("GetCurrentDirectoryW returned an empty string.\n");
3857         return;
3858     }
3859     lstrcatW(path, filename);
3860     SHGetDesktopFolder(&psf_desktop);
3861
3862     CreateFilesFolders();
3863
3864     hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, path, NULL, &pidl, 0);
3865     ok(hr == S_OK || broken(hr == E_FAIL) /* WinME */, "Got 0x%08x\n", hr);
3866     if(SUCCEEDED(hr))
3867     {
3868         IShellFolder *psf;
3869         LPCITEMIDLIST pidl_child;
3870         hr = pSHBindToParent(pidl, &IID_IShellFolder, (void**)&psf, &pidl_child);
3871         ok(hr == S_OK, "Got 0x%08x\n", hr);
3872         if(SUCCEEDED(hr))
3873         {
3874             hr = IShellFolder_GetUIObjectOf(psf, NULL, 1, (LPCITEMIDLIST*)&pidl_child,
3875                                             &IID_IContextMenu, NULL, (void**)&pcm);
3876             ok(hr == S_OK, "Got 0x%08x\n", hr);
3877             if(SUCCEEDED(hr))
3878             {
3879                 HMENU hmenu = CreatePopupMenu();
3880                 INT max_id, max_id_check;
3881                 UINT count, i;
3882                 const int id_upper_limit = 32767;
3883                 hr = IContextMenu_QueryContextMenu(pcm, hmenu, 0, 0, id_upper_limit, CMF_NORMAL);
3884                 ok(SUCCEEDED(hr), "Got 0x%08x\n", hr);
3885                 max_id = HRESULT_CODE(hr) - 1; /* returns max_id + 1 */
3886                 ok(max_id <= id_upper_limit, "Got %d\n", max_id);
3887                 count = GetMenuItemCount(hmenu);
3888                 ok(count, "Got %d\n", count);
3889
3890                 max_id_check = 0;
3891                 for(i = 0; i < count; i++)
3892                 {
3893                     MENUITEMINFOA mii;
3894                     INT res;
3895                     ZeroMemory(&mii, sizeof(MENUITEMINFOA));
3896                     mii.cbSize = sizeof(MENUITEMINFOA);
3897                     mii.fMask = MIIM_ID | MIIM_FTYPE;
3898
3899                     SetLastError(0);
3900                     res = GetMenuItemInfoA(hmenu, i, TRUE, &mii);
3901                     ok(res, "Failed (last error: %d).\n", GetLastError());
3902
3903                     ok( (mii.wID <= id_upper_limit) || (mii.fType & MFT_SEPARATOR),
3904                         "Got non-separator ID out of range: %d (type: %x)\n", mii.wID, mii.fType);
3905                     if(!(mii.fType & MFT_SEPARATOR))
3906                         max_id_check = (mii.wID>max_id_check)?mii.wID:max_id_check;
3907                 }
3908                 ok((max_id_check == max_id) ||
3909                    (max_id_check == max_id-1 /* Win 7 */),
3910                    "Not equal (or near equal), got %d and %d\n", max_id_check, max_id);
3911
3912 #define is_win2k() (pSHGetFolderPathA && !pSHGetFolderPathAndSubDirA)
3913
3914                 if(count && !is_win2k())   /* Test is interactive on w2k, so skip */
3915                 {
3916                     CMINVOKECOMMANDINFO cmi;
3917                     ZeroMemory(&cmi, sizeof(CMINVOKECOMMANDINFO));
3918                     cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
3919
3920                     /* Attempt to execute a nonexistent command */
3921                     cmi.lpVerb = MAKEINTRESOURCEA(9999);
3922                     hr = IContextMenu_InvokeCommand(pcm, &cmi);
3923                     ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3924
3925                     cmi.lpVerb = "foobar_wine_test";
3926                     hr = IContextMenu_InvokeCommand(pcm, &cmi);
3927                     ok( (hr == E_INVALIDARG) || (hr == E_FAIL /* Win7 */) ||
3928                         (hr == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION) /* Vista */),
3929                         "Got 0x%08x\n", hr);
3930                 }
3931 #undef is_win2k
3932
3933                 DestroyMenu(hmenu);
3934                 IContextMenu_Release(pcm);
3935             }
3936             IShellFolder_Release(psf);
3937         }
3938         if(pILFree) pILFree(pidl);
3939     }
3940
3941     IShellFolder_Release(psf_desktop);
3942     Cleanup();
3943 }
3944
3945 #define verify_pidl(i,p) r_verify_pidl(__LINE__, i, p)
3946 static void r_verify_pidl(unsigned l, LPCITEMIDLIST pidl, const WCHAR *path)
3947 {
3948     LPCITEMIDLIST child;
3949     IShellFolder *parent;
3950     STRRET filename;
3951     HRESULT hr;
3952
3953     if(!pSHBindToParent){
3954         win_skip("SHBindToParent is not available, not performing full PIDL verification\n");
3955         if(path)
3956             ok_(__FILE__,l)(pidl != NULL, "Expected PIDL to be non-NULL\n");
3957         else
3958             ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
3959         return;
3960     }
3961
3962     if(path){
3963         if(!pidl){
3964             ok_(__FILE__,l)(0, "didn't get expected path (%s), instead: NULL\n", wine_dbgstr_w(path));
3965             return;
3966         }
3967
3968         hr = pSHBindToParent(pidl, &IID_IShellFolder, (LPVOID*)&parent, &child);
3969         ok_(__FILE__,l)(hr == S_OK, "SHBindToParent failed: 0x%08x\n", hr);
3970         if(FAILED(hr))
3971             return;
3972
3973         hr = IShellFolder_GetDisplayNameOf(parent, child, SHGDN_FORPARSING, &filename);
3974         ok_(__FILE__,l)(hr == S_OK, "GetDisplayNameOf failed: 0x%08x\n", hr);
3975         if(FAILED(hr)){
3976             IShellFolder_Release(parent);
3977             return;
3978         }
3979
3980         ok_(__FILE__,l)(filename.uType == STRRET_WSTR || filename.uType == STRRET_CSTR,
3981                 "Got unexpected string type: %d\n", filename.uType);
3982         if(filename.uType == STRRET_WSTR){
3983             ok_(__FILE__,l)(lstrcmpW(path, U(filename).pOleStr) == 0,
3984                     "didn't get expected path (%s), instead: %s\n",
3985                      wine_dbgstr_w(path), wine_dbgstr_w(U(filename).pOleStr));
3986             SHFree(U(filename).pOleStr);
3987         }else if(filename.uType == STRRET_CSTR){
3988             ok_(__FILE__,l)(strcmp_wa(path, U(filename).cStr) == 0,
3989                     "didn't get expected path (%s), instead: %s\n",
3990                      wine_dbgstr_w(path), U(filename).cStr);
3991         }
3992
3993         IShellFolder_Release(parent);
3994     }else
3995         ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
3996 }
3997
3998 static void test_SHSimpleIDListFromPath(void)
3999 {
4000     const WCHAR adirW[] = {'C',':','\\','s','i','d','l','f','p','d','i','r',0};
4001     const CHAR adirA[] = "C:\\sidlfpdir";
4002     BOOL br, is_unicode = !(GetVersion() & 0x80000000);
4003
4004     LPITEMIDLIST pidl = NULL;
4005
4006     if(!pSHSimpleIDListFromPathAW){
4007         win_skip("SHSimpleIDListFromPathAW not available\n");
4008         return;
4009     }
4010
4011     br = CreateDirectoryA(adirA, NULL);
4012     ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
4013
4014     if(is_unicode)
4015         pidl = pSHSimpleIDListFromPathAW(adirW);
4016     else
4017         pidl = pSHSimpleIDListFromPathAW(adirA);
4018     verify_pidl(pidl, adirW);
4019     pILFree(pidl);
4020
4021     br = RemoveDirectoryA(adirA);
4022     ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4023
4024     if(is_unicode)
4025         pidl = pSHSimpleIDListFromPathAW(adirW);
4026     else
4027         pidl = pSHSimpleIDListFromPathAW(adirA);
4028     verify_pidl(pidl, adirW);
4029     pILFree(pidl);
4030 }
4031
4032 /* IFileSystemBindData impl */
4033 static HRESULT WINAPI fsbd_QueryInterface(IFileSystemBindData *fsbd,
4034         REFIID riid, void **ppv)
4035 {
4036     if(IsEqualIID(riid, &IID_IFileSystemBindData) ||
4037             IsEqualIID(riid, &IID_IUnknown)){
4038         *ppv = fsbd;
4039         return S_OK;
4040     }
4041     return E_NOINTERFACE;
4042 }
4043
4044 static ULONG WINAPI fsbd_AddRef(IFileSystemBindData *fsbd)
4045 {
4046     return 2;
4047 }
4048
4049 static ULONG WINAPI fsbd_Release(IFileSystemBindData *fsbd)
4050 {
4051     return 1;
4052 }
4053
4054 static HRESULT WINAPI fsbd_SetFindData(IFileSystemBindData *fsbd,
4055         const WIN32_FIND_DATAW *pfd)
4056 {
4057     ok(0, "SetFindData called\n");
4058     return E_NOTIMPL;
4059 }
4060
4061 static HRESULT WINAPI fsbd_GetFindData_nul(IFileSystemBindData *fsbd,
4062         WIN32_FIND_DATAW *pfd)
4063 {
4064     memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
4065     return S_OK;
4066 }
4067
4068 static HRESULT WINAPI fsbd_GetFindData_junk(IFileSystemBindData *fsbd,
4069         WIN32_FIND_DATAW *pfd)
4070 {
4071     memset(pfd, 0xef, sizeof(WIN32_FIND_DATAW));
4072     return S_OK;
4073 }
4074
4075 static HRESULT WINAPI fsbd_GetFindData_invalid(IFileSystemBindData *fsbd,
4076         WIN32_FIND_DATAW *pfd)
4077 {
4078     memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
4079     *pfd->cFileName = 'a';
4080     *pfd->cAlternateFileName = 'a';
4081     return S_OK;
4082 }
4083
4084 static HRESULT WINAPI fsbd_GetFindData_valid(IFileSystemBindData *fsbd,
4085         WIN32_FIND_DATAW *pfd)
4086 {
4087     static const WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4088     HANDLE handle = FindFirstFileW(adirW, pfd);
4089     FindClose(handle);
4090     return S_OK;
4091 }
4092
4093 static HRESULT WINAPI fsbd_GetFindData_fail(IFileSystemBindData *fsbd,
4094         WIN32_FIND_DATAW *pfd)
4095 {
4096     return E_FAIL;
4097 }
4098
4099 static IFileSystemBindDataVtbl fsbdVtbl = {
4100     fsbd_QueryInterface,
4101     fsbd_AddRef,
4102     fsbd_Release,
4103     fsbd_SetFindData,
4104     NULL
4105 };
4106
4107 static IFileSystemBindData fsbd = { &fsbdVtbl };
4108
4109 static void test_ParseDisplayNamePBC(void)
4110 {
4111     WCHAR wFileSystemBindData[] =
4112         {'F','i','l','e',' ','S','y','s','t','e','m',' ','B','i','n','d',' ','D','a','t','a',0};
4113     WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4114     WCHAR afileW[] = {'C',':','\\','f','s','b','d','d','i','r','\\','f','i','l','e','.','t','x','t',0};
4115     WCHAR afile2W[] = {'C',':','\\','f','s','b','d','d','i','r','\\','s','\\','f','i','l','e','.','t','x','t',0};
4116     const HRESULT exp_err = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
4117
4118     IShellFolder *psf;
4119     IBindCtx *pbc;
4120     HRESULT hres;
4121     ITEMIDLIST *pidl;
4122
4123     /* Check if we support WCHAR functions */
4124     SetLastError(0xdeadbeef);
4125     lstrcmpiW(adirW, adirW);
4126     if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED){
4127         win_skip("Most W-calls are not implemented\n");
4128         return;
4129     }
4130
4131     hres = SHGetDesktopFolder(&psf);
4132     ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
4133     if(FAILED(hres)){
4134         win_skip("Failed to get IShellFolder, can't run tests\n");
4135         return;
4136     }
4137
4138     /* fails on unknown dir with no IBindCtx */
4139     hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, adirW, NULL, &pidl, NULL);
4140     ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4141             "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4142     hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, afileW, NULL, &pidl, NULL);
4143     ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4144             "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4145     hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, afile2W, NULL, &pidl, NULL);
4146     ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4147             "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4148
4149     /* fails on unknown dir with IBindCtx with no IFileSystemBindData */
4150     hres = CreateBindCtx(0, &pbc);
4151     ok(hres == S_OK, "CreateBindCtx failed: 0x%08x\n", hres);
4152
4153     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4154     ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4155             "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4156     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4157     ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4158             "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4159     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4160     ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4161             "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4162
4163     /* unknown dir with IBindCtx with IFileSystemBindData */
4164     hres = IBindCtx_RegisterObjectParam(pbc, wFileSystemBindData, (IUnknown*)&fsbd);
4165     ok(hres == S_OK, "RegisterObjectParam failed: 0x%08x\n", hres);
4166
4167     /* return E_FAIL from GetFindData */
4168     pidl = (ITEMIDLIST*)0xdeadbeef;
4169     fsbdVtbl.GetFindData = fsbd_GetFindData_fail;
4170     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, 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, adirW);
4175         ILFree(pidl);
4176     }
4177
4178     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, 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, afileW);
4183         ILFree(pidl);
4184     }
4185
4186     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4187     ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4188             "ParseDisplayName failed: 0x%08x\n", hres);
4189     if(SUCCEEDED(hres)){
4190         verify_pidl(pidl, afile2W);
4191         ILFree(pidl);
4192     }
4193
4194     /* set FIND_DATA struct to NULLs */
4195     pidl = (ITEMIDLIST*)0xdeadbeef;
4196     fsbdVtbl.GetFindData = fsbd_GetFindData_nul;
4197     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, 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, adirW);
4202         ILFree(pidl);
4203     }
4204
4205     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, 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, afileW);
4210         ILFree(pidl);
4211     }
4212
4213     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4214     ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4215             "ParseDisplayName failed: 0x%08x\n", hres);
4216     if(SUCCEEDED(hres)){
4217         verify_pidl(pidl, afile2W);
4218         ILFree(pidl);
4219     }
4220
4221     /* set FIND_DATA struct to junk */
4222     pidl = (ITEMIDLIST*)0xdeadbeef;
4223     fsbdVtbl.GetFindData = fsbd_GetFindData_junk;
4224     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, 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, adirW);
4229         ILFree(pidl);
4230     }
4231
4232     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, 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, afileW);
4237         ILFree(pidl);
4238     }
4239
4240     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4241     ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4242             "ParseDisplayName failed: 0x%08x\n", hres);
4243     if(SUCCEEDED(hres)){
4244         verify_pidl(pidl, afile2W);
4245         ILFree(pidl);
4246     }
4247
4248     /* set FIND_DATA struct to invalid data */
4249     pidl = (ITEMIDLIST*)0xdeadbeef;
4250     fsbdVtbl.GetFindData = fsbd_GetFindData_invalid;
4251     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, 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, adirW);
4256         ILFree(pidl);
4257     }
4258
4259     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, 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, afileW);
4264         ILFree(pidl);
4265     }
4266
4267     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4268     ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4269             "ParseDisplayName failed: 0x%08x\n", hres);
4270     if(SUCCEEDED(hres)){
4271         verify_pidl(pidl, afile2W);
4272         ILFree(pidl);
4273     }
4274
4275     /* set FIND_DATA struct to valid data */
4276     pidl = (ITEMIDLIST*)0xdeadbeef;
4277     fsbdVtbl.GetFindData = fsbd_GetFindData_valid;
4278     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, 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, adirW);
4283         ILFree(pidl);
4284     }
4285
4286     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, 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, afileW);
4291         ILFree(pidl);
4292     }
4293
4294     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4295     ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4296             "ParseDisplayName failed: 0x%08x\n", hres);
4297     if(SUCCEEDED(hres)){
4298         verify_pidl(pidl, afile2W);
4299         ILFree(pidl);
4300     }
4301
4302     IBindCtx_Release(pbc);
4303     IShellFolder_Release(psf);
4304 }
4305
4306 static const CHAR testwindow_class[] = "testwindow";
4307 #define WM_USER_NOTIFY (WM_APP+1)
4308
4309 struct ChNotifyTest {
4310     const char id[256];
4311     const UINT notify_count;
4312     UINT missing_events;
4313     UINT signal;
4314     const char path_1[256];
4315     const char path_2[256];
4316 } chnotify_tests[] = {
4317     {"MKDIR", 1, 0, SHCNE_MKDIR, "C:\\shell32_cn_test\\test", ""},
4318     {"CREATE", 1, 0, SHCNE_CREATE, "C:\\shell32_cn_test\\test\\file.txt", ""},
4319     {"RMDIR", 1, 0, SHCNE_RMDIR, "C:\\shell32_cn_test\\test", ""},
4320 };
4321
4322 struct ChNotifyTest *exp_data;
4323
4324 static LRESULT CALLBACK testwindow_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
4325 {
4326     UINT signal = (UINT)lparam;
4327
4328     switch(msg){
4329     case WM_USER_NOTIFY:
4330         if(exp_data->missing_events > 0){
4331             WCHAR *path1, *path2;
4332             LPCITEMIDLIST *pidls = (LPCITEMIDLIST*)wparam;
4333
4334             ok(exp_data->signal == signal,
4335                     "%s: expected notification type %x, got: %x\n",
4336                     exp_data->id, exp_data->signal, signal);
4337
4338             trace("verifying pidls for: %s\n", exp_data->id);
4339             path1 = make_wstr(exp_data->path_1);
4340             path2 = make_wstr(exp_data->path_2);
4341             verify_pidl(pidls[0], path1);
4342             verify_pidl(pidls[1], path2);
4343             HeapFree(GetProcessHeap(), 0, path1);
4344             HeapFree(GetProcessHeap(), 0, path2);
4345
4346             exp_data->missing_events--;
4347         }else
4348             ok(0, "Didn't expect a WM_USER_NOTIFY message (event: %x)\n", signal);
4349         return 0;
4350     }
4351     return DefWindowProc(hwnd, msg, wparam, lparam);
4352 }
4353
4354 static void register_testwindow_class(void)
4355 {
4356     WNDCLASSEXA cls;
4357     ATOM ret;
4358
4359     ZeroMemory(&cls, sizeof(cls));
4360     cls.cbSize = sizeof(cls);
4361     cls.style = 0;
4362     cls.lpfnWndProc = testwindow_wndproc;
4363     cls.hInstance = GetModuleHandleA(NULL);
4364     cls.lpszClassName = testwindow_class;
4365
4366     SetLastError(0);
4367     ret = RegisterClassExA(&cls);
4368     ok(ret != 0, "RegisterClassExA failed: %d\n", GetLastError());
4369 }
4370
4371 /* SHCNF_FLUSH doesn't seem to work as advertised for SHCNF_PATHA, so we
4372  * have to poll repeatedly for the message to appear */
4373 static void do_events(void)
4374 {
4375     int c = 0;
4376     while (exp_data->missing_events && (c++ < 10)){
4377         MSG msg;
4378         while(PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)){
4379             TranslateMessage(&msg);
4380             DispatchMessageA(&msg);
4381         }
4382         if(exp_data->missing_events)
4383             Sleep(500);
4384     }
4385     trace("%s: took %d tries\n", exp_data->id, c);
4386 }
4387
4388 static void test_SHChangeNotify(void)
4389 {
4390     HWND wnd;
4391     ULONG notifyID, i;
4392     HRESULT hr;
4393     BOOL br, has_unicode;
4394     SHChangeNotifyEntry entries[1];
4395     const CHAR root_dirA[] = "C:\\shell32_cn_test";
4396     const WCHAR root_dirW[] = {'C',':','\\','s','h','e','l','l','3','2','_','c','n','_','t','e','s','t',0};
4397
4398     CreateDirectoryW(NULL, NULL);
4399     has_unicode = !(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED);
4400
4401     register_testwindow_class();
4402
4403     wnd = CreateWindowExA(0, testwindow_class, testwindow_class, 0,
4404             CW_USEDEFAULT, CW_USEDEFAULT, 130, 105,
4405             NULL, NULL, GetModuleHandleA(NULL), 0);
4406     ok(wnd != NULL, "Failed to make a window\n");
4407
4408     br = CreateDirectoryA(root_dirA, NULL);
4409     ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
4410
4411     entries[0].pidl = NULL;
4412     if(has_unicode)
4413         hr = SHILCreateFromPath(root_dirW, (LPITEMIDLIST*)&entries[0].pidl, 0);
4414     else
4415         hr = SHILCreateFromPath((LPCVOID)root_dirA, (LPITEMIDLIST*)&entries[0].pidl, 0);
4416     ok(hr == S_OK, "SHILCreateFromPath failed: 0x%08x\n", hr);
4417     entries[0].fRecursive = TRUE;
4418
4419     notifyID = SHChangeNotifyRegister(wnd, SHCNRF_ShellLevel,
4420             SHCNE_ALLEVENTS, WM_USER_NOTIFY, 1, entries);
4421     ok(notifyID != 0, "Failed to register a window for change notifications\n");
4422
4423     for(i = 0; i < sizeof(chnotify_tests) / sizeof(*chnotify_tests); ++i){
4424         exp_data = chnotify_tests + i;
4425
4426         exp_data->missing_events = exp_data->notify_count;
4427         SHChangeNotify(exp_data->signal, SHCNF_PATHA | SHCNF_FLUSH,
4428                 strlen(exp_data->path_1) > 0 ? exp_data->path_1 : NULL,
4429                 strlen(exp_data->path_2) > 0 ? exp_data->path_2 : NULL);
4430         do_events();
4431         ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
4432
4433         if(has_unicode){
4434             WCHAR *path1, *path2;
4435
4436             path1 = make_wstr(exp_data->path_1);
4437             path2 = make_wstr(exp_data->path_2);
4438
4439             exp_data->missing_events = exp_data->notify_count;
4440             SHChangeNotify(exp_data->signal, SHCNF_PATHW | SHCNF_FLUSH, path1, path2);
4441             do_events();
4442             ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
4443
4444             HeapFree(GetProcessHeap(), 0, path1);
4445             HeapFree(GetProcessHeap(), 0, path2);
4446         }
4447     }
4448
4449     SHChangeNotifyDeregister(notifyID);
4450     DestroyWindow(wnd);
4451
4452     ILFree((LPITEMIDLIST)entries[0].pidl);
4453     br = RemoveDirectoryA(root_dirA);
4454     ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4455 }
4456
4457 START_TEST(shlfolder)
4458 {
4459     init_function_pointers();
4460     /* if OleInitialize doesn't get called, ParseDisplayName returns
4461        CO_E_NOTINITIALIZED for malformed directory names on win2k. */
4462     OleInitialize(NULL);
4463
4464     test_ParseDisplayName();
4465     test_SHParseDisplayName();
4466     test_BindToObject();
4467     test_EnumObjects_and_CompareIDs();
4468     test_GetDisplayName();
4469     test_GetAttributesOf();
4470     test_SHGetPathFromIDList();
4471     test_CallForAttributes();
4472     test_FolderShortcut();
4473     test_ITEMIDLIST_format();
4474     test_SHGetFolderPathA();
4475     test_SHGetFolderPathAndSubDirA();
4476     test_LocalizedNames();
4477     test_SHCreateShellItem();
4478     test_SHCreateShellItemArray();
4479     test_desktop_IPersist();
4480     test_GetUIObject();
4481     test_SHSimpleIDListFromPath();
4482     test_ParseDisplayNamePBC();
4483     test_SHGetNameFromIDList();
4484     test_SHGetItemFromDataObject();
4485     test_SHGetIDListFromObject();
4486     test_SHGetItemFromObject();
4487     test_ShellItemCompare();
4488     test_SHChangeNotify();
4489     test_ShellItemBindToHandler();
4490     test_ShellItemGetAttributes();
4491
4492     OleUninitialize();
4493 }