include/msvcrt: Define more CPU control word flags.
[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 cwd[MAX_PATH];
444     WCHAR path[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 WCHAR filename_html[] = {'w','i','n','e','t','e','s','t','.','h','t','m','l',0};
450     static const WCHAR filename_txt[] = {'w','i','n','e','t','e','s','t','.','t','x','t',0};
451     static const WCHAR filename_foo[] = {'w','i','n','e','t','e','s','t','.','f','o','o',0};
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     MultiByteToWideChar(CP_ACP, 0, buf, -1, cwd, MAX_PATH);
531
532     SHGetDesktopFolder(&psfDesktop);
533
534     /* Attempt BindToObject on files. */
535
536     /* .html */
537     lstrcpyW(path, cwd);
538     myPathAddBackslashW(path);
539     lstrcatW(path, filename_html);
540     hfile = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
541     if(hfile != (HANDLE)INVALID_FILE_ATTRIBUTES)
542     {
543         CloseHandle(hfile);
544         hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
545         ok(hr == S_OK ||
546            broken(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) /* Win98SE */ ||
547            broken(hr == E_FAIL) /* Win95 */,
548            "Got 0x%08x\n", hr);
549         if(SUCCEEDED(hr))
550         {
551             hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
552             ok(hr == S_OK /* Win 7 */ || hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) /* WinXP */,
553                "Got 0x%08x\n", hr);
554             if(SUCCEEDED(hr))
555             {
556                 IPersist *pp;
557                 hr = IShellFolder_QueryInterface(psfChild, &IID_IPersist, (void**)&pp);
558                 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* W2K */, "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         DeleteFileW(path);
573     }
574     else
575         win_skip("Failed to create .html testfile.\n");
576
577     /* .txt */
578     lstrcpyW(path, cwd);
579     myPathAddBackslashW(path);
580     lstrcatW(path, filename_txt);
581     hfile = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
582     if(hfile != (HANDLE)INVALID_FILE_ATTRIBUTES)
583     {
584         CloseHandle(hfile);
585         hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
586         ok(hr == S_OK ||
587            broken(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) /* Win98SE */ ||
588            broken(hr == E_FAIL) /* Win95 */,
589            "Got 0x%08x\n", hr);
590         if(SUCCEEDED(hr))
591         {
592             hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
593             ok(hr == E_FAIL || hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)
594                || broken(hr == S_OK) /* W2K */,
595                "Got 0x%08x\n", hr);
596             if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
597             pILFree(pidl);
598         }
599         DeleteFileW(path);
600     }
601     else
602         win_skip("Failed to create .txt testfile.\n");
603
604     /* .foo */
605     lstrcpyW(path, cwd);
606     myPathAddBackslashW(path);
607     lstrcatW(path, filename_foo);
608     hfile = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
609     if(hfile != (HANDLE)INVALID_FILE_ATTRIBUTES)
610     {
611         CloseHandle(hfile);
612         hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
613         ok(hr == S_OK ||
614            broken(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) /* Win98SE */ ||
615            broken(hr == E_FAIL) /* Win95 */,
616            "Got 0x%08x\n", hr);
617         if(SUCCEEDED(hr))
618         {
619             hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
620             ok(hr == E_FAIL || hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)
621                || broken(hr == S_OK) /* W2K */,
622                "Got 0x%08x\n", hr);
623             if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
624             pILFree(pidl);
625         }
626         DeleteFileW(path);
627     }
628     else
629         win_skip("Failed to create .foo testfile.\n");
630
631     /* And on the desktop */
632     if(pSHGetSpecialFolderPathW)
633     {
634
635         pSHGetSpecialFolderPathW(NULL, path, CSIDL_DESKTOP, FALSE);
636         myPathAddBackslashW(path);
637         lstrcatW(path, filename_html);
638         hfile = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
639         if(hfile != (HANDLE)INVALID_FILE_ATTRIBUTES)
640         {
641             CloseHandle(hfile);
642             hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
643             ok(hr == S_OK || broken(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) /* Win98SE */,
644                "Got 0x%08x\n", hr);
645             if(SUCCEEDED(hr))
646             {
647                 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
648                 ok(hr == S_OK || hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
649                    "Got 0x%08x\n", hr);
650                 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
651                 pILFree(pidl);
652             }
653             if(!DeleteFileW(path))
654                 trace("Failed to delete: %d\n", GetLastError());
655
656         }
657         else
658             win_skip("Failed to create .html testfile.\n");
659
660         pSHGetSpecialFolderPathW(NULL, path, CSIDL_DESKTOP, FALSE);
661         myPathAddBackslashW(path);
662         lstrcatW(path, filename_foo);
663         hfile = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
664         if(hfile != (HANDLE)INVALID_FILE_ATTRIBUTES)
665         {
666             CloseHandle(hfile);
667             hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
668             ok(hr == S_OK || broken(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) /* Win98SE */,
669                "Got 0x%08x\n", hr);
670             if(SUCCEEDED(hr))
671             {
672                 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
673                 ok(hr == E_FAIL || hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)
674                    || broken(hr == S_OK) /* W2K */,
675                    "Got 0x%08x\n", hr);
676                 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
677                 pILFree(pidl);
678             }
679             DeleteFileW(path);
680         }
681         else
682             win_skip("Failed to create .foo testfile.\n");
683     }
684
685     IShellFolder_Release(psfDesktop);
686 }
687
688 static void test_GetDisplayName(void)
689 {
690     BOOL result;
691     HRESULT hr;
692     HANDLE hTestFile;
693     WCHAR wszTestFile[MAX_PATH], wszTestFile2[MAX_PATH];
694     char szTestFile[MAX_PATH], szTestDir[MAX_PATH];
695     DWORD attr;
696     STRRET strret;
697     LPSHELLFOLDER psfDesktop, psfPersonal;
698     IUnknown *psfFile;
699     SHITEMID emptyitem = { 0, { 0 } };
700     LPITEMIDLIST pidlTestFile, pidlEmpty = (LPITEMIDLIST)&emptyitem;
701     LPCITEMIDLIST pidlLast;
702     static const CHAR szFileName[] = "winetest.foo";
703     static const WCHAR wszFileName[] = { 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
704     static const WCHAR wszDirName[] = { 'w','i','n','e','t','e','s','t',0 };
705
706     /* I'm trying to figure if there is a functional difference between calling
707      * SHGetPathFromIDListW and calling GetDisplayNameOf(SHGDN_FORPARSING) after
708      * binding to the shellfolder. One thing I thought of was that perhaps 
709      * SHGetPathFromIDListW would be able to get the path to a file, which does
710      * not exist anymore, while the other method wouldn't. It turns out there's
711      * no functional difference in this respect.
712      */
713
714     if(!pSHGetSpecialFolderPathA) {
715         win_skip("SHGetSpecialFolderPathA is not available\n");
716         return;
717     }
718
719     /* First creating a directory in MyDocuments and a file in this directory. */
720     result = pSHGetSpecialFolderPathA(NULL, szTestDir, CSIDL_PERSONAL, FALSE);
721     ok(result, "SHGetSpecialFolderPathA failed! Last error: %u\n", GetLastError());
722     if (!result) return;
723
724     /* Use ANSI file functions so this works on Windows 9x */
725     lstrcatA(szTestDir, "\\winetest");
726     CreateDirectoryA(szTestDir, NULL);
727     attr=GetFileAttributesA(szTestDir);
728     if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY))
729     {
730         ok(0, "unable to create the '%s' directory\n", szTestDir);
731         return;
732     }
733
734     lstrcpyA(szTestFile, szTestDir);
735     lstrcatA(szTestFile, "\\");
736     lstrcatA(szTestFile, szFileName);
737     hTestFile = CreateFileA(szTestFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
738     ok((hTestFile != INVALID_HANDLE_VALUE), "CreateFileA failed! Last error: %u\n", GetLastError());
739     if (hTestFile == INVALID_HANDLE_VALUE) return;
740     CloseHandle(hTestFile);
741
742     /* Getting an itemidlist for the file. */
743     hr = SHGetDesktopFolder(&psfDesktop);
744     ok(hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
745     if (hr != S_OK) return;
746
747     MultiByteToWideChar(CP_ACP, 0, szTestFile, -1, wszTestFile, MAX_PATH);
748
749     hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
750     ok(hr == S_OK, "Desktop->ParseDisplayName failed! hr = %08x\n", hr);
751     if (hr != S_OK) {
752         IShellFolder_Release(psfDesktop);
753         return;
754     }
755
756     pidlLast = pILFindLastID(pidlTestFile);
757     ok(pidlLast->mkid.cb >=76 ||
758         broken(pidlLast->mkid.cb == 28) || /* W2K */
759         broken(pidlLast->mkid.cb == 40), /* Win9x, WinME */
760         "Expected pidl length of at least 76, got %d.\n", pidlLast->mkid.cb);
761     if (pidlLast->mkid.cb >= 28) {
762         ok(!lstrcmpA((CHAR*)&pidlLast->mkid.abID[12], szFileName),
763             "Filename should be stored as ansi-string at this position!\n");
764     }
765     /* WinXP and up store the filenames as both ANSI and UNICODE in the pidls */
766     if (pidlLast->mkid.cb >= 76) {
767         ok(!lstrcmpW((WCHAR*)&pidlLast->mkid.abID[46], wszFileName) ||
768             (pidlLast->mkid.cb >= 94 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[64], wszFileName)) ||  /* Vista */
769             (pidlLast->mkid.cb >= 98 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[68], wszFileName)), /* Win7 */
770             "Filename should be stored as wchar-string at this position!\n");
771     }
772     
773     /* It seems as if we cannot bind to regular files on windows, but only directories. 
774      */
775     hr = IShellFolder_BindToObject(psfDesktop, pidlTestFile, NULL, &IID_IUnknown, (VOID**)&psfFile);
776     ok (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
777         hr == E_NOTIMPL || /* Vista */
778         broken(hr == S_OK), /* Win9x, W2K */
779         "hr = %08x\n", hr);
780     if (hr == S_OK) {
781         IShellFolder_Release(psfFile);
782     }
783
784     if (!pSHBindToParent)
785     {
786         win_skip("SHBindToParent is missing\n");
787         DeleteFileA(szTestFile);
788         RemoveDirectoryA(szTestDir);
789         return;
790     }
791   
792     /* Some tests for IShellFolder::SetNameOf */
793     if (pSHGetFolderPathAndSubDirA)
794     {
795         hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
796         ok(hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
797         if (hr == S_OK) {
798             /* It's ok to use this fixed path. Call will fail anyway. */
799             WCHAR wszAbsoluteFilename[] = { 'C',':','\\','w','i','n','e','t','e','s','t', 0 };
800             LPITEMIDLIST pidlNew;
801
802             /* The pidl returned through the last parameter of SetNameOf is a simple one. */
803             hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlLast, wszDirName, SHGDN_NORMAL, &pidlNew);
804             ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
805             if (hr == S_OK)
806             {
807                 ok (((LPITEMIDLIST)((LPBYTE)pidlNew+pidlNew->mkid.cb))->mkid.cb == 0,
808                     "pidl returned from SetNameOf should be simple!\n");
809
810                 /* Passing an absolute path to SetNameOf fails. The HRESULT code indicates that SetNameOf
811                  * is implemented on top of SHFileOperation in WinXP. */
812                 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszAbsoluteFilename,
813                         SHGDN_FORPARSING, NULL);
814                 ok (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED), "SetNameOf succeeded! hr = %08x\n", hr);
815
816                 /* Rename the file back to its original name. SetNameOf ignores the fact, that the
817                  * SHGDN flags specify an absolute path. */
818                 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszFileName, SHGDN_FORPARSING, NULL);
819                 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
820
821                 pILFree(pidlNew);
822             }
823
824             IShellFolder_Release(psfPersonal);
825         }
826     }
827     else
828         win_skip("Avoid needs of interaction on Win2k\n");
829
830     /* Deleting the file and the directory */
831     DeleteFileA(szTestFile);
832     RemoveDirectoryA(szTestDir);
833
834     /* SHGetPathFromIDListW still works, although the file is not present anymore. */
835     if (pSHGetPathFromIDListW)
836     {
837         result = pSHGetPathFromIDListW(pidlTestFile, wszTestFile2);
838         ok (result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
839         ok (!lstrcmpiW(wszTestFile, wszTestFile2), "SHGetPathFromIDListW returns incorrect path!\n");
840     }
841
842     /* SHBindToParent fails, if called with a NULL PIDL. */
843     hr = pSHBindToParent(NULL, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
844     ok (hr != S_OK, "SHBindToParent(NULL) should fail!\n");
845
846     /* But it succeeds with an empty PIDL. */
847     hr = pSHBindToParent(pidlEmpty, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
848     ok (hr == S_OK, "SHBindToParent(empty PIDL) should succeed! hr = %08x\n", hr);
849     ok (pidlLast == pidlEmpty, "The last element of an empty PIDL should be the PIDL itself!\n");
850     if (hr == S_OK)
851         IShellFolder_Release(psfPersonal);
852     
853     /* Binding to the folder and querying the display name of the file also works. */
854     hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast); 
855     ok (hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
856     if (hr != S_OK) {
857         IShellFolder_Release(psfDesktop);
858         return;
859     }
860
861     /* This test shows that Windows doesn't allocate a new pidlLast, but returns a pointer into 
862      * pidlTestFile (In accordance with MSDN). */
863     ok (pILFindLastID(pidlTestFile) == pidlLast, 
864                                 "SHBindToParent doesn't return the last id of the pidl param!\n");
865     
866     hr = IShellFolder_GetDisplayNameOf(psfPersonal, pidlLast, SHGDN_FORPARSING, &strret);
867     ok (hr == S_OK, "Personal->GetDisplayNameOf failed! hr = %08x\n", hr);
868     if (hr != S_OK) {
869         IShellFolder_Release(psfDesktop);
870         IShellFolder_Release(psfPersonal);
871         return;
872     }
873
874     if (pStrRetToBufW)
875     {
876         hr = pStrRetToBufW(&strret, pidlLast, wszTestFile2, MAX_PATH);
877         ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
878         ok (!lstrcmpiW(wszTestFile, wszTestFile2), "GetDisplayNameOf returns incorrect path!\n");
879     }
880     
881     ILFree(pidlTestFile);
882     IShellFolder_Release(psfDesktop);
883     IShellFolder_Release(psfPersonal);
884 }
885
886 static void test_CallForAttributes(void)
887 {
888     HKEY hKey;
889     LONG lResult;
890     HRESULT hr;
891     DWORD dwSize;
892     LPSHELLFOLDER psfDesktop;
893     LPITEMIDLIST pidlMyDocuments;
894     DWORD dwAttributes, dwCallForAttributes, dwOrigAttributes, dwOrigCallForAttributes;
895     static const WCHAR wszAttributes[] = { 'A','t','t','r','i','b','u','t','e','s',0 };
896     static const WCHAR wszCallForAttributes[] = { 
897         'C','a','l','l','F','o','r','A','t','t','r','i','b','u','t','e','s',0 };
898     static const WCHAR wszMyDocumentsKey[] = {
899         'C','L','S','I','D','\\','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-',
900         '1','1','D','0','-','9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',
901         '\\','S','h','e','l','l','F','o','l','d','e','r',0 };
902     WCHAR wszMyDocuments[] = {
903         ':',':','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-','1','1','D','0','-',
904         '9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',0 };
905     
906     /* For the root of a namespace extension, the attributes are not queried by binding
907      * to the object and calling GetAttributesOf. Instead, the attributes are read from 
908      * the registry value HKCR/CLSID/{...}/ShellFolder/Attributes. This is documented on MSDN.
909      *
910      * The MyDocuments shellfolder on WinXP has a HKCR/CLSID/{...}/ShellFolder/CallForAttributes
911      * value. It seems that if the folder is queried for one of the flags set in CallForAttributes,
912      * the shell does bind to the folder object and calls GetAttributesOf. This is not documented
913      * on MSDN. This test is meant to document the observed behaviour on WinXP SP2.
914      */
915     hr = SHGetDesktopFolder(&psfDesktop);
916     ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
917     if (hr != S_OK) return;
918     
919     hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyDocuments, NULL, 
920                                        &pidlMyDocuments, NULL);
921     ok (hr == S_OK ||
922         broken(hr == E_INVALIDARG), /* Win95, NT4 */
923         "Desktop's ParseDisplayName failed to parse MyDocuments's CLSID! hr = %08x\n", hr);
924     if (hr != S_OK) {
925         IShellFolder_Release(psfDesktop);
926         return;
927     }
928
929     dwAttributes = 0xffffffff;
930     hr = IShellFolder_GetAttributesOf(psfDesktop, 1, 
931                                       (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
932     ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
933
934     /* We need the following setup (as observed on WinXP SP2), for the tests to make sense. */
935     ok (dwAttributes & SFGAO_FILESYSTEM, "SFGAO_FILESYSTEM attribute is not set for MyDocuments!\n");
936     ok (!(dwAttributes & SFGAO_ISSLOW), "SFGAO_ISSLOW attribute is set for MyDocuments!\n");
937     ok (!(dwAttributes & SFGAO_GHOSTED), "SFGAO_GHOSTED attribute is set for MyDocuments!\n");
938
939     /* We don't have the MyDocuments shellfolder in wine yet, and thus we don't have the registry
940      * key. So the test will return at this point, if run on wine. 
941      */
942     lResult = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszMyDocumentsKey, 0, KEY_WRITE|KEY_READ, &hKey);
943     ok (lResult == ERROR_SUCCESS ||
944         lResult == ERROR_ACCESS_DENIED,
945         "RegOpenKeyEx failed! result: %08x\n", lResult);
946     if (lResult != ERROR_SUCCESS) {
947         if (lResult == ERROR_ACCESS_DENIED)
948             skip("Not enough rights to open the registry key\n");
949         IMalloc_Free(ppM, pidlMyDocuments);
950         IShellFolder_Release(psfDesktop);
951         return;
952     }
953     
954     /* Query MyDocuments' Attributes value, to be able to restore it later. */
955     dwSize = sizeof(DWORD);
956     lResult = RegQueryValueExW(hKey, wszAttributes, NULL, NULL, (LPBYTE)&dwOrigAttributes, &dwSize);
957     ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
958     if (lResult != ERROR_SUCCESS) {
959         RegCloseKey(hKey);
960         IMalloc_Free(ppM, pidlMyDocuments);
961         IShellFolder_Release(psfDesktop);
962         return;
963     }
964
965     /* Query MyDocuments' CallForAttributes value, to be able to restore it later. */
966     dwSize = sizeof(DWORD);
967     lResult = RegQueryValueExW(hKey, wszCallForAttributes, NULL, NULL, 
968                               (LPBYTE)&dwOrigCallForAttributes, &dwSize);
969     ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
970     if (lResult != ERROR_SUCCESS) {
971         RegCloseKey(hKey);
972         IMalloc_Free(ppM, pidlMyDocuments);
973         IShellFolder_Release(psfDesktop);
974         return;
975     }
976     
977     /* Define via the Attributes value that MyDocuments attributes are SFGAO_ISSLOW and 
978      * SFGAO_GHOSTED and that MyDocuments should be called for the SFGAO_ISSLOW and
979      * SFGAO_FILESYSTEM attributes. */
980     dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED;
981     RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwAttributes, sizeof(DWORD));
982     dwCallForAttributes = SFGAO_ISSLOW|SFGAO_FILESYSTEM;
983     RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD, 
984                    (LPBYTE)&dwCallForAttributes, sizeof(DWORD));
985
986     /* Although it is not set in CallForAttributes, the SFGAO_GHOSTED flag is reset by 
987      * GetAttributesOf. It seems that once there is a single attribute queried, for which
988      * CallForAttributes is set, all flags are taken from the GetAttributesOf call and
989      * the flags in Attributes are ignored. 
990      */
991     dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED|SFGAO_FILESYSTEM;
992     hr = IShellFolder_GetAttributesOf(psfDesktop, 1, 
993                                       (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
994     ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
995     if (hr == S_OK)
996         ok (dwAttributes == SFGAO_FILESYSTEM, 
997             "Desktop->GetAttributes(MyDocuments) returned unexpected attributes: %08x\n", 
998             dwAttributes);
999
1000     /* Restore MyDocuments' original Attributes and CallForAttributes registry values */
1001     RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwOrigAttributes, sizeof(DWORD));
1002     RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD, 
1003                    (LPBYTE)&dwOrigCallForAttributes, sizeof(DWORD));
1004     RegCloseKey(hKey);
1005     IMalloc_Free(ppM, pidlMyDocuments);
1006     IShellFolder_Release(psfDesktop);
1007 }
1008
1009 static void test_GetAttributesOf(void) 
1010 {
1011     HRESULT hr;
1012     LPSHELLFOLDER psfDesktop, psfMyComputer;
1013     SHITEMID emptyitem = { 0, { 0 } };
1014     LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
1015     LPITEMIDLIST pidlMyComputer;
1016     DWORD dwFlags;
1017     static const DWORD desktopFlags[] = {
1018         /* WinXP */
1019         SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSANCESTOR |
1020         SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
1021         /* Win2k */
1022         SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_STREAM | SFGAO_FILESYSANCESTOR |
1023         SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
1024         /* WinMe, Win9x, WinNT*/
1025         SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSANCESTOR |
1026         SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
1027     };
1028     static const DWORD myComputerFlags[] = {
1029         /* WinXP */
1030         SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
1031         SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1032         /* Win2k */
1033         SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_STREAM |
1034         SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1035         /* WinMe, Win9x, WinNT */
1036         SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
1037         SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1038         /* Win95, WinNT when queried directly */
1039         SFGAO_CANLINK | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
1040         SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
1041     };
1042     WCHAR wszMyComputer[] = { 
1043         ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
1044         'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
1045     char  cCurrDirA [MAX_PATH] = {0};
1046     WCHAR cCurrDirW [MAX_PATH];
1047     static WCHAR cTestDirW[] = {'t','e','s','t','d','i','r',0};
1048     IShellFolder *IDesktopFolder, *testIShellFolder;
1049     ITEMIDLIST *newPIDL;
1050     int len, i;
1051     BOOL foundFlagsMatch;
1052
1053     hr = SHGetDesktopFolder(&psfDesktop);
1054     ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1055     if (hr != S_OK) return;
1056
1057     /* The Desktop attributes can be queried with a single empty itemidlist, .. */
1058     dwFlags = 0xffffffff;
1059     hr = IShellFolder_GetAttributesOf(psfDesktop, 1, &pidlEmpty, &dwFlags);
1060     ok (hr == S_OK, "Desktop->GetAttributesOf(empty pidl) failed! hr = %08x\n", hr);
1061     for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1062          i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
1063     {
1064         if (desktopFlags[i] == dwFlags)
1065             foundFlagsMatch = TRUE;
1066     }
1067     ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
1068
1069     /* .. or with no itemidlist at all. */
1070     dwFlags = 0xffffffff;
1071     hr = IShellFolder_GetAttributesOf(psfDesktop, 0, NULL, &dwFlags);
1072     ok (hr == S_OK, "Desktop->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
1073     for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1074          i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
1075     {
1076         if (desktopFlags[i] == dwFlags)
1077             foundFlagsMatch = TRUE;
1078     }
1079     ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
1080    
1081     /* Testing the attributes of the MyComputer shellfolder */
1082     hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1083     ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1084     if (hr != S_OK) {
1085         IShellFolder_Release(psfDesktop);
1086         return;
1087     }
1088
1089     /* Windows sets the SFGAO_CANLINK flag, when MyComputer is queried via the Desktop
1090      * folder object. It doesn't do this, if MyComputer is queried directly (see below).
1091      */
1092     dwFlags = 0xffffffff;
1093     hr = IShellFolder_GetAttributesOf(psfDesktop, 1, (LPCITEMIDLIST*)&pidlMyComputer, &dwFlags);
1094     ok (hr == S_OK, "Desktop->GetAttributesOf(MyComputer) failed! hr = %08x\n", hr);
1095     for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1096          i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
1097     {
1098         if ((myComputerFlags[i] | SFGAO_CANLINK) == dwFlags)
1099             foundFlagsMatch = TRUE;
1100     }
1101     todo_wine
1102     ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
1103
1104     hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
1105     ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
1106     IShellFolder_Release(psfDesktop);
1107     IMalloc_Free(ppM, pidlMyComputer);
1108     if (hr != S_OK) return;
1109
1110     hr = IShellFolder_GetAttributesOf(psfMyComputer, 1, &pidlEmpty, &dwFlags);
1111     todo_wine
1112     ok (hr == E_INVALIDARG ||
1113         broken(hr == S_OK), /* W2K and earlier */
1114         "MyComputer->GetAttributesOf(emtpy pidl) should fail! hr = %08x\n", hr);
1115
1116     dwFlags = 0xffffffff;
1117     hr = IShellFolder_GetAttributesOf(psfMyComputer, 0, NULL, &dwFlags);
1118     ok (hr == S_OK, "MyComputer->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
1119     for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1120          i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
1121     {
1122         if (myComputerFlags[i] == dwFlags)
1123             foundFlagsMatch = TRUE;
1124     }
1125     todo_wine
1126     ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
1127
1128     IShellFolder_Release(psfMyComputer);
1129
1130     GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1131     len = lstrlenA(cCurrDirA);
1132
1133     if (len == 0) {
1134         win_skip("GetCurrentDirectoryA returned empty string. Skipping test_GetAttributesOf\n");
1135         return;
1136     }
1137     if (len > 3 && cCurrDirA[len-1] == '\\')
1138         cCurrDirA[len-1] = 0;
1139
1140     /* create test directory */
1141     CreateFilesFolders();
1142
1143     MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1144  
1145     hr = SHGetDesktopFolder(&IDesktopFolder);
1146     ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1147
1148     hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1149     ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1150
1151     hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1152     ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1153
1154     IMalloc_Free(ppM, newPIDL);
1155
1156     /* get relative PIDL */
1157     hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1158     ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1159
1160     /* test the shell attributes of the test directory using the relative PIDL */
1161     dwFlags = SFGAO_FOLDER;
1162     hr = IShellFolder_GetAttributesOf(testIShellFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
1163     ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
1164     ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for relative PIDL: %08x\n", dwFlags);
1165
1166     /* free memory */
1167     IMalloc_Free(ppM, newPIDL);
1168
1169     /* append testdirectory name to path */
1170     if (cCurrDirA[len-1] == '\\')
1171         cCurrDirA[len-1] = 0;
1172     lstrcatA(cCurrDirA, "\\testdir");
1173     MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1174
1175     hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1176     ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1177
1178     /* test the shell attributes of the test directory using the absolute PIDL */
1179     dwFlags = SFGAO_FOLDER;
1180     hr = IShellFolder_GetAttributesOf(IDesktopFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
1181     ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
1182     ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for absolute PIDL: %08x\n", dwFlags);
1183
1184     /* free memory */
1185     IMalloc_Free(ppM, newPIDL);
1186
1187     IShellFolder_Release(testIShellFolder);
1188
1189     Cleanup();
1190
1191     IShellFolder_Release(IDesktopFolder);
1192 }
1193
1194 static void test_SHGetPathFromIDList(void)
1195 {
1196     SHITEMID emptyitem = { 0, { 0 } };
1197     LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
1198     LPITEMIDLIST pidlMyComputer;
1199     WCHAR wszPath[MAX_PATH], wszDesktop[MAX_PATH];
1200     BOOL result;
1201     HRESULT hr;
1202     LPSHELLFOLDER psfDesktop;
1203     WCHAR wszMyComputer[] = { 
1204         ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
1205         'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
1206     WCHAR wszFileName[MAX_PATH];
1207     LPITEMIDLIST pidlTestFile;
1208     HANDLE hTestFile;
1209     STRRET strret;
1210     static WCHAR wszTestFile[] = {
1211         'w','i','n','e','t','e','s','t','.','f','o','o',0 };
1212     LPITEMIDLIST pidlPrograms;
1213
1214     if(!pSHGetPathFromIDListW || !pSHGetSpecialFolderPathW)
1215     {
1216         win_skip("SHGetPathFromIDListW() or SHGetSpecialFolderPathW() is missing\n");
1217         return;
1218     }
1219
1220     /* Calling SHGetPathFromIDListW with no pidl should return the empty string */
1221     wszPath[0] = 'a';
1222     wszPath[1] = '\0';
1223     result = pSHGetPathFromIDListW(NULL, wszPath);
1224     ok(!result, "Expected failure\n");
1225     ok(!wszPath[0], "Expected empty string\n");
1226
1227     /* Calling SHGetPathFromIDListW with an empty pidl should return the desktop folder's path. */
1228     result = pSHGetSpecialFolderPathW(NULL, wszDesktop, CSIDL_DESKTOP, FALSE);
1229     ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOP) failed! Last error: %u\n", GetLastError());
1230     if (!result) return;
1231
1232     /* Check if we are on Win9x */
1233     SetLastError(0xdeadbeef);
1234     lstrcmpiW(wszDesktop, wszDesktop);
1235     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1236     {
1237         win_skip("Most W-calls are not implemented\n");
1238         return;
1239     }
1240
1241     result = pSHGetPathFromIDListW(pidlEmpty, wszPath);
1242     ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1243     if (!result) return;
1244     ok(!lstrcmpiW(wszDesktop, wszPath), "SHGetPathFromIDListW didn't return desktop path for empty pidl!\n");
1245
1246     /* MyComputer does not map to a filesystem path. SHGetPathFromIDListW should fail. */
1247     hr = SHGetDesktopFolder(&psfDesktop);
1248     ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1249     if (hr != S_OK) return;
1250
1251     hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1252     ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1253     if (hr != S_OK) {
1254         IShellFolder_Release(psfDesktop);
1255         return;
1256     }
1257
1258     SetLastError(0xdeadbeef);
1259     wszPath[0] = 'a';
1260     wszPath[1] = '\0';
1261     result = pSHGetPathFromIDListW(pidlMyComputer, wszPath);
1262     ok (!result, "SHGetPathFromIDListW succeeded where it shouldn't!\n");
1263     ok (GetLastError()==0xdeadbeef ||
1264         GetLastError()==ERROR_SUCCESS, /* Vista and higher */
1265         "Unexpected last error from SHGetPathFromIDListW: %u\n", GetLastError());
1266     ok (!wszPath[0], "Expected empty path\n");
1267     if (result) {
1268         IShellFolder_Release(psfDesktop);
1269         return;
1270     }
1271
1272     IMalloc_Free(ppM, pidlMyComputer);
1273
1274     result = pSHGetSpecialFolderPathW(NULL, wszFileName, CSIDL_DESKTOPDIRECTORY, FALSE);
1275     ok(result, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1276     if (!result) {
1277         IShellFolder_Release(psfDesktop);
1278         return;
1279     }
1280     myPathAddBackslashW(wszFileName);
1281     lstrcatW(wszFileName, wszTestFile);
1282     hTestFile = CreateFileW(wszFileName, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
1283     ok(hTestFile != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: %u\n", GetLastError());
1284     if (hTestFile == INVALID_HANDLE_VALUE) {
1285         IShellFolder_Release(psfDesktop);
1286         return;
1287     }
1288     CloseHandle(hTestFile);
1289
1290     hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
1291     ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse filename hr = %08x\n", hr);
1292     if (hr != S_OK) {
1293         IShellFolder_Release(psfDesktop);
1294         DeleteFileW(wszFileName);
1295         IMalloc_Free(ppM, pidlTestFile);
1296         return;
1297     }
1298
1299     /* This test is to show that the Desktop shellfolder prepends the CSIDL_DESKTOPDIRECTORY
1300      * path for files placed on the desktop, if called with SHGDN_FORPARSING. */
1301     hr = IShellFolder_GetDisplayNameOf(psfDesktop, pidlTestFile, SHGDN_FORPARSING, &strret);
1302     ok (hr == S_OK, "Desktop's GetDisplayNamfOf failed! hr = %08x\n", hr);
1303     IShellFolder_Release(psfDesktop);
1304     DeleteFileW(wszFileName);
1305     if (hr != S_OK) {
1306         IMalloc_Free(ppM, pidlTestFile);
1307         return;
1308     }
1309     if (pStrRetToBufW)
1310     {
1311         pStrRetToBufW(&strret, pidlTestFile, wszPath, MAX_PATH);
1312         ok(0 == lstrcmpW(wszFileName, wszPath), 
1313            "Desktop->GetDisplayNameOf(pidlTestFile, SHGDN_FORPARSING) "
1314            "returned incorrect path for file placed on desktop\n");
1315     }
1316
1317     result = pSHGetPathFromIDListW(pidlTestFile, wszPath);
1318     ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1319     IMalloc_Free(ppM, pidlTestFile);
1320     if (!result) return;
1321     ok(0 == lstrcmpW(wszFileName, wszPath), "SHGetPathFromIDListW returned incorrect path for file placed on desktop\n");
1322
1323
1324     /* Test if we can get the path from the start menu "program files" PIDL. */
1325     hr = pSHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidlPrograms);
1326     ok(hr == S_OK, "SHGetFolderLocation failed: 0x%08x\n", hr);
1327
1328     SetLastError(0xdeadbeef);
1329     result = pSHGetPathFromIDListW(pidlPrograms, wszPath);
1330         IMalloc_Free(ppM, pidlPrograms);
1331     ok(result, "SHGetPathFromIDListW failed\n");
1332 }
1333
1334 static void test_EnumObjects_and_CompareIDs(void)
1335 {
1336     ITEMIDLIST *newPIDL;
1337     IShellFolder *IDesktopFolder, *testIShellFolder;
1338     char  cCurrDirA [MAX_PATH] = {0};
1339     static const CHAR cTestDirA[] = "\\testdir";
1340     WCHAR cTestDirW[MAX_PATH];
1341     int len;
1342     HRESULT hr;
1343
1344     GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1345     len = lstrlenA(cCurrDirA);
1346
1347     if(len == 0) {
1348         win_skip("GetCurrentDirectoryA returned empty string. Skipping test_EnumObjects_and_CompareIDs\n");
1349         return;
1350     }
1351     if(cCurrDirA[len-1] == '\\')
1352         cCurrDirA[len-1] = 0;
1353
1354     lstrcatA(cCurrDirA, cTestDirA);
1355     MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cTestDirW, MAX_PATH);
1356
1357     hr = SHGetDesktopFolder(&IDesktopFolder);
1358     ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1359
1360     CreateFilesFolders();
1361
1362     hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1363     ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1364
1365     hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1366     ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1367
1368     test_EnumObjects(testIShellFolder);
1369
1370     IShellFolder_Release(testIShellFolder);
1371
1372     Cleanup();
1373
1374     IMalloc_Free(ppM, newPIDL);
1375
1376     IShellFolder_Release(IDesktopFolder);
1377 }
1378
1379 /* A simple implementation of an IPropertyBag, which returns fixed values for
1380  * 'Target' and 'Attributes' properties.
1381  */
1382 static HRESULT WINAPI InitPropertyBag_IPropertyBag_QueryInterface(IPropertyBag *iface, REFIID riid,
1383     void **ppvObject) 
1384 {
1385     if (!ppvObject)
1386         return E_INVALIDARG;
1387
1388     if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPropertyBag, riid)) {
1389         *ppvObject = iface;
1390     } else {
1391         ok (FALSE, "InitPropertyBag asked for unknown interface!\n");
1392         return E_NOINTERFACE;
1393     }
1394
1395     IPropertyBag_AddRef(iface);
1396     return S_OK;
1397 }
1398
1399 static ULONG WINAPI InitPropertyBag_IPropertyBag_AddRef(IPropertyBag *iface) {
1400     return 2;
1401 }
1402
1403 static ULONG WINAPI InitPropertyBag_IPropertyBag_Release(IPropertyBag *iface) {
1404     return 1;
1405 }
1406
1407 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Read(IPropertyBag *iface, LPCOLESTR pszPropName,
1408     VARIANT *pVar, IErrorLog *pErrorLog)
1409 {
1410     static const WCHAR wszTargetSpecialFolder[] = {
1411         'T','a','r','g','e','t','S','p','e','c','i','a','l','F','o','l','d','e','r',0 };
1412     static const WCHAR wszTarget[] = {
1413         'T','a','r','g','e','t',0 };
1414     static const WCHAR wszAttributes[] = {
1415         'A','t','t','r','i','b','u','t','e','s',0 };
1416     static const WCHAR wszResolveLinkFlags[] = {
1417         'R','e','s','o','l','v','e','L','i','n','k','F','l','a','g','s',0 };
1418     static const WCHAR wszTargetKnownFolder[] = {
1419         'T','a','r','g','e','t','K','n','o','w','n','F','o','l','d','e','r',0 };
1420     static const WCHAR wszCLSID[] = {
1421         'C','L','S','I','D',0 };
1422        
1423     if (!lstrcmpW(pszPropName, wszTargetSpecialFolder)) {
1424         ok(V_VT(pVar) == VT_I4 ||
1425            broken(V_VT(pVar) == VT_BSTR),   /* Win2k */
1426            "Wrong variant type for 'TargetSpecialFolder' property!\n");
1427         return E_INVALIDARG;
1428     }
1429     
1430     if (!lstrcmpW(pszPropName, wszResolveLinkFlags)) 
1431     {
1432         ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'ResolveLinkFlags' property!\n");
1433         return E_INVALIDARG;
1434     }
1435
1436     if (!lstrcmpW(pszPropName, wszTarget)) {
1437         WCHAR wszPath[MAX_PATH];
1438         BOOL result;
1439         
1440         ok(V_VT(pVar) == VT_BSTR ||
1441            broken(V_VT(pVar) == VT_EMPTY),  /* Win2k */
1442            "Wrong variant type for 'Target' property!\n");
1443         if (V_VT(pVar) != VT_BSTR) return E_INVALIDARG;
1444
1445         result = pSHGetSpecialFolderPathW(NULL, wszPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1446         ok(result, "SHGetSpecialFolderPathW(DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1447         if (!result) return E_INVALIDARG;
1448
1449         V_BSTR(pVar) = SysAllocString(wszPath);
1450         return S_OK;
1451     }
1452
1453     if (!lstrcmpW(pszPropName, wszAttributes)) {
1454         ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'Attributes' property!\n");
1455         if (V_VT(pVar) != VT_UI4) return E_INVALIDARG;
1456         V_UI4(pVar) = SFGAO_FOLDER|SFGAO_HASSUBFOLDER|SFGAO_FILESYSANCESTOR|
1457                       SFGAO_CANRENAME|SFGAO_FILESYSTEM;
1458         return S_OK;
1459     }
1460
1461     if (!lstrcmpW(pszPropName, wszTargetKnownFolder)) {
1462         ok(V_VT(pVar) == VT_BSTR, "Wrong variant type for 'TargetKnownFolder' property!\n");
1463         /* TODO */
1464         return E_INVALIDARG;
1465     }
1466
1467     if (!lstrcmpW(pszPropName, wszCLSID)) {
1468         ok(V_VT(pVar) == VT_EMPTY, "Wrong variant type for 'CLSID' property!\n");
1469         /* TODO */
1470         return E_INVALIDARG;
1471     }
1472
1473     ok(FALSE, "PropertyBag was asked for unknown property %s (vt=%d)!\n", wine_dbgstr_w(pszPropName), V_VT(pVar));
1474     return E_INVALIDARG;
1475 }
1476
1477 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Write(IPropertyBag *iface, LPCOLESTR pszPropName,
1478     VARIANT *pVar)
1479 {
1480     ok(FALSE, "Unexpected call to IPropertyBag_Write\n");
1481     return E_NOTIMPL;
1482 }
1483     
1484 static const IPropertyBagVtbl InitPropertyBag_IPropertyBagVtbl = {
1485     InitPropertyBag_IPropertyBag_QueryInterface,
1486     InitPropertyBag_IPropertyBag_AddRef,
1487     InitPropertyBag_IPropertyBag_Release,
1488     InitPropertyBag_IPropertyBag_Read,
1489     InitPropertyBag_IPropertyBag_Write
1490 };
1491
1492 static struct IPropertyBag InitPropertyBag = {
1493     &InitPropertyBag_IPropertyBagVtbl
1494 };
1495
1496 static void test_FolderShortcut(void) {
1497     IPersistPropertyBag *pPersistPropertyBag;
1498     IShellFolder *pShellFolder, *pDesktopFolder;
1499     IPersistFolder3 *pPersistFolder3;
1500     HRESULT hr;
1501     STRRET strret;
1502     WCHAR wszDesktopPath[MAX_PATH], wszBuffer[MAX_PATH];
1503     BOOL result;
1504     CLSID clsid;
1505     LPITEMIDLIST pidlCurrentFolder, pidlWineTestFolder, pidlSubFolder;
1506     HKEY hShellExtKey;
1507     WCHAR wszWineTestFolder[] = {
1508         ':',':','{','9','B','3','5','2','E','B','F','-','2','7','6','5','-','4','5','C','1','-',
1509         'B','4','C','6','-','8','5','C','C','7','F','7','A','B','C','6','4','}',0 };
1510     WCHAR wszShellExtKey[] = { 'S','o','f','t','w','a','r','e','\\',
1511         'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
1512         'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1513         'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
1514         'N','a','m','e','S','p','a','c','e','\\',
1515         '{','9','b','3','5','2','e','b','f','-','2','7','6','5','-','4','5','c','1','-',
1516         'b','4','c','6','-','8','5','c','c','7','f','7','a','b','c','6','4','}',0 };
1517     
1518     WCHAR wszSomeSubFolder[] = { 'S','u','b','F','o','l','d','e','r', 0};
1519     static const GUID CLSID_UnixDosFolder = 
1520         {0x9d20aae8, 0x0625, 0x44b0, {0x9c, 0xa7, 0x71, 0x88, 0x9c, 0x22, 0x54, 0xd9}};
1521
1522     if (!pSHGetSpecialFolderPathW || !pStrRetToBufW) {
1523         win_skip("SHGetSpecialFolderPathW and/or StrRetToBufW are not available\n");
1524         return;
1525     }
1526
1527     if (!pSHGetFolderPathAndSubDirA)
1528     {
1529         win_skip("FolderShortcut test doesn't work on Win2k\n");
1530         return;
1531     }
1532
1533     /* These tests basically show, that CLSID_FolderShortcuts are initialized
1534      * via their IPersistPropertyBag interface. And that the target folder
1535      * is taken from the IPropertyBag's 'Target' property.
1536      */
1537     hr = CoCreateInstance(&CLSID_FolderShortcut, NULL, CLSCTX_INPROC_SERVER, 
1538                           &IID_IPersistPropertyBag, (LPVOID*)&pPersistPropertyBag);
1539     if (hr == REGDB_E_CLASSNOTREG) {
1540         win_skip("CLSID_FolderShortcut is not implemented\n");
1541         return;
1542     }
1543     ok (hr == S_OK, "CoCreateInstance failed! hr = 0x%08x\n", hr);
1544     if (hr != S_OK) return;
1545
1546     hr = IPersistPropertyBag_Load(pPersistPropertyBag, &InitPropertyBag, NULL);
1547     ok(hr == S_OK, "IPersistPropertyBag_Load failed! hr = %08x\n", hr);
1548     if (hr != S_OK) {
1549         IPersistPropertyBag_Release(pPersistPropertyBag);
1550         return;
1551     }
1552
1553     hr = IPersistPropertyBag_QueryInterface(pPersistPropertyBag, &IID_IShellFolder, 
1554                                             (LPVOID*)&pShellFolder);
1555     IPersistPropertyBag_Release(pPersistPropertyBag);
1556     ok(hr == S_OK, "IPersistPropertyBag_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1557     if (hr != S_OK) return;
1558
1559     hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1560     ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1561     if (hr != S_OK) {
1562         IShellFolder_Release(pShellFolder);
1563         return;
1564     }
1565
1566     result = pSHGetSpecialFolderPathW(NULL, wszDesktopPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1567     ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1568     if (!result) return;
1569
1570     pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1571     ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1572
1573     hr = IShellFolder_QueryInterface(pShellFolder, &IID_IPersistFolder3, (LPVOID*)&pPersistFolder3);
1574     IShellFolder_Release(pShellFolder);
1575     ok(hr == S_OK, "IShellFolder_QueryInterface(IID_IPersistFolder3 failed! hr = 0x%08x\n", hr);
1576     if (hr != S_OK) return;
1577
1578     hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1579     ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1580     ok(IsEqualCLSID(&clsid, &CLSID_FolderShortcut), "Unexpected CLSID!\n");
1581
1582     hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1583     todo_wine ok(hr == S_FALSE, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1584     ok(!pidlCurrentFolder, "IPersistFolder3_GetCurFolder should return a NULL pidl!\n");
1585                     
1586     /* For FolderShortcut objects, the Initialize method initialized the folder's position in the
1587      * shell namespace. The target folder, read from the property bag above, remains untouched. 
1588      * The following tests show this: The itemidlist for some imaginary shellfolder object
1589      * is created and the FolderShortcut is initialized with it. GetCurFolder now returns this
1590      * itemidlist, but GetDisplayNameOf still returns the path from above.
1591      */
1592     hr = SHGetDesktopFolder(&pDesktopFolder);
1593     ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1594     if (hr != S_OK) return;
1595
1596     /* Temporarily register WineTestFolder as a shell namespace extension at the Desktop. 
1597      * Otherwise ParseDisplayName fails on WinXP with E_INVALIDARG */
1598     RegCreateKeyW(HKEY_CURRENT_USER, wszShellExtKey, &hShellExtKey);
1599     RegCloseKey(hShellExtKey);
1600     hr = IShellFolder_ParseDisplayName(pDesktopFolder, NULL, NULL, wszWineTestFolder, NULL,
1601                                        &pidlWineTestFolder, NULL);
1602     RegDeleteKeyW(HKEY_CURRENT_USER, wszShellExtKey);
1603     IShellFolder_Release(pDesktopFolder);
1604     ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1605     if (hr != S_OK) return;
1606
1607     hr = IPersistFolder3_Initialize(pPersistFolder3, pidlWineTestFolder);
1608     ok (hr == S_OK, "IPersistFolder3::Initialize failed! hr = %08x\n", hr);
1609     if (hr != S_OK) {
1610         IPersistFolder3_Release(pPersistFolder3);
1611         pILFree(pidlWineTestFolder);
1612         return;
1613     }
1614
1615     hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1616     ok(hr == S_OK, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1617     ok(pILIsEqual(pidlCurrentFolder, pidlWineTestFolder),
1618         "IPersistFolder3_GetCurFolder should return pidlWineTestFolder!\n");
1619     pILFree(pidlCurrentFolder);
1620     pILFree(pidlWineTestFolder);
1621
1622     hr = IPersistFolder3_QueryInterface(pPersistFolder3, &IID_IShellFolder, (LPVOID*)&pShellFolder);
1623     IPersistFolder3_Release(pPersistFolder3);
1624     ok(hr == S_OK, "IPersistFolder3_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1625     if (hr != S_OK) return;
1626
1627     hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1628     ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1629     if (hr != S_OK) {
1630         IShellFolder_Release(pShellFolder);
1631         return;
1632     }
1633
1634     pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1635     ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1636
1637     /* Next few lines are meant to show that children of FolderShortcuts are not FolderShortcuts,
1638      * but ShellFSFolders. */
1639     myPathAddBackslashW(wszDesktopPath);
1640     lstrcatW(wszDesktopPath, wszSomeSubFolder);
1641     if (!CreateDirectoryW(wszDesktopPath, NULL)) {
1642         IShellFolder_Release(pShellFolder);
1643         return;
1644     }
1645     
1646     hr = IShellFolder_ParseDisplayName(pShellFolder, NULL, NULL, wszSomeSubFolder, NULL, 
1647                                        &pidlSubFolder, NULL);
1648     RemoveDirectoryW(wszDesktopPath);
1649     ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1650     if (hr != S_OK) {
1651         IShellFolder_Release(pShellFolder);
1652         return;
1653     }
1654
1655     hr = IShellFolder_BindToObject(pShellFolder, pidlSubFolder, NULL, &IID_IPersistFolder3,
1656                                    (LPVOID*)&pPersistFolder3);
1657     IShellFolder_Release(pShellFolder);
1658     pILFree(pidlSubFolder);
1659     ok (hr == S_OK, "IShellFolder::BindToObject failed! hr = %08x\n", hr);
1660     if (hr != S_OK)
1661         return;
1662
1663     /* On windows, we expect CLSID_ShellFSFolder. On wine we relax this constraint
1664      * a little bit and also allow CLSID_UnixDosFolder. */
1665     hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1666     ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1667     ok(IsEqualCLSID(&clsid, &CLSID_ShellFSFolder) || IsEqualCLSID(&clsid, &CLSID_UnixDosFolder),
1668         "IPersistFolder3::GetClassID returned unexpected CLSID!\n");
1669
1670     IPersistFolder3_Release(pPersistFolder3);
1671 }
1672
1673 #include "pshpack1.h"
1674 struct FileStructA {
1675     BYTE  type;
1676     BYTE  dummy;
1677     DWORD dwFileSize;
1678     WORD  uFileDate;    /* In our current implementation this is */
1679     WORD  uFileTime;    /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastWriteTime) */
1680     WORD  uFileAttribs;
1681     CHAR  szName[1];
1682 };
1683
1684 struct FileStructW {
1685     WORD  cbLen;        /* Length of this element. */
1686     BYTE  abFooBar1[6]; /* Beyond any recognition. */
1687     WORD  uDate;        /* FileTimeToDosDate(WIN32_FIND_DATA->ftCreationTime)? */
1688     WORD  uTime;        /* (this is currently speculation) */
1689     WORD  uDate2;       /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastAccessTime)? */
1690     WORD  uTime2;       /* (this is currently speculation) */
1691     BYTE  abFooBar2[4]; /* Beyond any recognition. */
1692     WCHAR wszName[1];   /* The long filename in unicode. */
1693     /* Just for documentation: Right after the unicode string: */
1694     WORD  cbOffset;     /* FileStructW's offset from the beginning of the SHITMEID. 
1695                          * SHITEMID->cb == uOffset + cbLen */
1696 };
1697 #include "poppack.h"
1698
1699 static void test_ITEMIDLIST_format(void) {
1700     WCHAR wszPersonal[MAX_PATH];
1701     LPSHELLFOLDER psfDesktop, psfPersonal;
1702     LPITEMIDLIST pidlPersonal, pidlFile;
1703     HANDLE hFile;
1704     HRESULT hr;
1705     BOOL bResult;
1706     WCHAR wszFile[3][17] = { { 'e','v','e','n','_',0 }, { 'o','d','d','_',0 },
1707         { 'l','o','n','g','e','r','_','t','h','a','n','.','8','_','3',0 } };
1708     int i;
1709
1710     if (!pSHGetSpecialFolderPathW) return;
1711
1712     bResult = pSHGetSpecialFolderPathW(NULL, wszPersonal, CSIDL_PERSONAL, FALSE);
1713     ok(bResult, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1714     if (!bResult) return;
1715
1716     SetLastError(0xdeadbeef);
1717     bResult = SetCurrentDirectoryW(wszPersonal);
1718     if (!bResult && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
1719         win_skip("Most W-calls are not implemented\n");
1720         return;
1721     }
1722     ok(bResult, "SetCurrentDirectory failed! Last error: %u\n", GetLastError());
1723     if (!bResult) return;
1724
1725     hr = SHGetDesktopFolder(&psfDesktop);
1726     ok(hr == S_OK, "SHGetDesktopFolder failed! hr: %08x\n", hr);
1727     if (hr != S_OK) return;
1728
1729     hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszPersonal, NULL, &pidlPersonal, NULL);
1730     ok(hr == S_OK, "psfDesktop->ParseDisplayName failed! hr = %08x\n", hr);
1731     if (hr != S_OK) {
1732         IShellFolder_Release(psfDesktop);
1733         return;
1734     }
1735
1736     hr = IShellFolder_BindToObject(psfDesktop, pidlPersonal, NULL, &IID_IShellFolder,
1737         (LPVOID*)&psfPersonal);
1738     IShellFolder_Release(psfDesktop);
1739     pILFree(pidlPersonal);
1740     ok(hr == S_OK, "psfDesktop->BindToObject failed! hr = %08x\n", hr);
1741     if (hr != S_OK) return;
1742
1743     for (i=0; i<3; i++) {
1744         CHAR szFile[MAX_PATH];
1745         struct FileStructA *pFileStructA;
1746         WORD cbOffset;
1747
1748         WideCharToMultiByte(CP_ACP, 0, wszFile[i], -1, szFile, MAX_PATH, NULL, NULL);
1749
1750         hFile = CreateFileW(wszFile[i], GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_FLAG_WRITE_THROUGH, NULL);
1751         ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed! (%u)\n", GetLastError());
1752         if (hFile == INVALID_HANDLE_VALUE) {
1753             IShellFolder_Release(psfPersonal);
1754             return;
1755         }
1756         CloseHandle(hFile);
1757
1758         hr = IShellFolder_ParseDisplayName(psfPersonal, NULL, NULL, wszFile[i], NULL, &pidlFile, NULL);
1759         DeleteFileW(wszFile[i]);
1760         ok(hr == S_OK, "psfPersonal->ParseDisplayName failed! hr: %08x\n", hr);
1761         if (hr != S_OK) {
1762             IShellFolder_Release(psfPersonal);
1763             return;
1764         }
1765
1766         pFileStructA = (struct FileStructA *)pidlFile->mkid.abID;
1767         ok(pFileStructA->type == 0x32, "PIDLTYPE should be 0x32!\n");
1768         ok(pFileStructA->dummy == 0x00, "Dummy Byte should be 0x00!\n");
1769         ok(pFileStructA->dwFileSize == 0, "Filesize should be zero!\n");
1770
1771         if (i < 2) /* First two file names are already in valid 8.3 format */
1772             ok(!strcmp(szFile, (CHAR*)&pidlFile->mkid.abID[12]), "Wrong file name!\n");
1773         else
1774             /* WinXP stores a derived 8.3 dos name (LONGER~1.8_3) here. We probably
1775              * can't implement this correctly, since unix filesystems don't support
1776              * this nasty short/long filename stuff. So we'll probably stay with our
1777              * current habbit of storing the long filename here, which seems to work
1778              * just fine. */
1779             todo_wine
1780             ok(pidlFile->mkid.abID[18] == '~' ||
1781                broken(pidlFile->mkid.abID[34] == '~'),  /* Win2k */
1782                "Should be derived 8.3 name!\n");
1783
1784         if (i == 0) /* First file name has an even number of chars. No need for alignment. */
1785             ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] != '\0' ||
1786                broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1),    /* Win2k */
1787                 "Alignment byte, where there shouldn't be!\n");
1788
1789         if (i == 1) /* Second file name has an uneven number of chars => alignment byte */
1790             ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] == '\0',
1791                 "There should be an alignment byte, but isn't!\n");
1792
1793         /* The offset of the FileStructW member is stored as a WORD at the end of the pidl. */
1794         cbOffset = *(WORD*)(((LPBYTE)pidlFile)+pidlFile->mkid.cb-sizeof(WORD));
1795         ok ((cbOffset >= sizeof(struct FileStructA) &&
1796             cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW)) ||
1797             broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1) ||     /* Win2k on short names */
1798             broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 12 + 1),  /* Win2k on long names */
1799             "Wrong offset value (%d) stored at the end of the PIDL\n", cbOffset);
1800
1801         if (cbOffset >= sizeof(struct FileStructA) &&
1802             cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW))
1803         {
1804             struct FileStructW *pFileStructW = (struct FileStructW *)(((LPBYTE)pidlFile)+cbOffset);
1805
1806             ok(pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen,
1807                 "FileStructW's offset and length should add up to the PIDL's length!\n");
1808
1809             if (pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen) {
1810                 /* Since we just created the file, time of creation,
1811                  * time of last access and time of last write access just be the same.
1812                  * These tests seem to fail sometimes (on WinXP), if the test is run again shortly
1813                  * after the first run. I do remember something with NTFS keeping the creation time
1814                  * if a file is deleted and then created again within a couple of seconds or so.
1815                  * Might be the reason. */
1816                 ok (pFileStructA->uFileDate == pFileStructW->uDate &&
1817                     pFileStructA->uFileTime == pFileStructW->uTime,
1818                     "Last write time should match creation time!\n");
1819
1820                 /* On FAT filesystems the last access time is midnight
1821                    local time, so the values of uDate2 and uTime2 will
1822                    depend on the local timezone.  If the times are exactly
1823                    equal then the dates should be identical for both FAT
1824                    and NTFS as no timezone is more than 1 day away from UTC.
1825                 */
1826                 if (pFileStructA->uFileTime == pFileStructW->uTime2)
1827                 {
1828                     ok (pFileStructA->uFileDate == pFileStructW->uDate2,
1829                         "Last write date and time should match last access date and time!\n");
1830                 }
1831                 else
1832                 {
1833                     /* Filesystem may be FAT. Check date within 1 day
1834                        and seconds are zero. */
1835                     trace ("Filesystem may be FAT. Performing less strict atime test.\n");
1836                     ok ((pFileStructW->uTime2 & 0x1F) == 0,
1837                         "Last access time on FAT filesystems should have zero seconds.\n");
1838                     /* TODO: Perform check for date being within one day.*/
1839                 }
1840
1841                 ok (!lstrcmpW(wszFile[i], pFileStructW->wszName) ||
1842                     !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 22)) || /* Vista */
1843                     !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 26)), /* Win7 */
1844                     "The filename should be stored in unicode at this position!\n");
1845             }
1846         }
1847
1848         pILFree(pidlFile);
1849     }
1850
1851     IShellFolder_Release(psfPersonal);
1852 }
1853
1854 static void test_SHGetFolderPathA(void)
1855 {
1856     static const BOOL is_win64 = sizeof(void *) > sizeof(int);
1857     BOOL is_wow64;
1858     char path[MAX_PATH];
1859     char path_x86[MAX_PATH];
1860     char path_key[MAX_PATH];
1861     HRESULT hr;
1862     HKEY key;
1863
1864     if (!pSHGetFolderPathA)
1865     {
1866         win_skip("SHGetFolderPathA not present\n");
1867         return;
1868     }
1869     if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
1870
1871     hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES, 0, SHGFP_TYPE_CURRENT, path );
1872     ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1873     hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILESX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
1874     if (hr == E_FAIL)
1875     {
1876         win_skip( "Program Files (x86) not supported\n" );
1877         return;
1878     }
1879     ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1880     if (is_win64)
1881     {
1882         ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1883         ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1884         ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1885     }
1886     else
1887     {
1888         ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1889         if (is_wow64)
1890             ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1891         else
1892             ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1893     }
1894     if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1895     {
1896         DWORD type, count = sizeof(path_x86);
1897         if (!RegQueryValueExA( key, "ProgramFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1898         {
1899             ok( is_win64 || is_wow64, "ProgramFilesDir (x86) exists on 32-bit setup\n" );
1900             ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1901         }
1902         else ok( !is_win64 && !is_wow64, "ProgramFilesDir (x86) should exist on 64-bit setup\n" );
1903         RegCloseKey( key );
1904     }
1905
1906     hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMON, 0, SHGFP_TYPE_CURRENT, path );
1907     ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1908     hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMONX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
1909     if (hr == E_FAIL)
1910     {
1911         win_skip( "Common Files (x86) not supported\n" );
1912         return;
1913     }
1914     ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1915     if (is_win64)
1916     {
1917         ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1918         ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1919         ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1920     }
1921     else
1922     {
1923         ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1924         if (is_wow64)
1925             ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1926         else
1927             ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1928     }
1929     if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1930     {
1931         DWORD type, count = sizeof(path_x86);
1932         if (!RegQueryValueExA( key, "CommonFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1933         {
1934             ok( is_win64 || is_wow64, "CommonFilesDir (x86) exists on 32-bit setup\n" );
1935             ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1936         }
1937         else ok( !is_win64 && !is_wow64, "CommonFilesDir (x86) should exist on 64-bit setup\n" );
1938     }
1939 }
1940
1941 static void test_SHGetFolderPathAndSubDirA(void)
1942 {
1943     HRESULT ret;
1944     BOOL delret;
1945     DWORD dwret;
1946     int i;
1947     static char wine[] = "wine";
1948     static char winetemp[] = "wine\\temp";
1949     static char appdata[MAX_PATH];
1950     static char testpath[MAX_PATH];
1951     static char toolongpath[MAX_PATH+1];
1952
1953     if(!pSHGetFolderPathAndSubDirA)
1954     {
1955         win_skip("SHGetFolderPathAndSubDirA not present!\n");
1956         return;
1957     }
1958
1959     if(!pSHGetFolderPathA) {
1960         win_skip("SHGetFolderPathA not present!\n");
1961         return;
1962     }
1963     if(FAILED(pSHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdata)))
1964     {
1965         win_skip("SHGetFolderPathA failed for CSIDL_LOCAL_APPDATA!\n");
1966         return;
1967     }
1968
1969     sprintf(testpath, "%s\\%s", appdata, winetemp);
1970     delret = RemoveDirectoryA(testpath);
1971     if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) ) {
1972         win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1973         return;
1974     }
1975
1976     sprintf(testpath, "%s\\%s", appdata, wine);
1977     delret = RemoveDirectoryA(testpath);
1978     if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) && (ERROR_FILE_NOT_FOUND != GetLastError())) {
1979         win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1980         return;
1981     }
1982
1983     /* test invalid second parameter */
1984     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | 0xff, NULL, SHGFP_TYPE_CURRENT, wine, testpath);
1985     ok(E_INVALIDARG == ret, "expected E_INVALIDARG, got  %x\n", ret);
1986
1987     /* test fourth parameter */
1988     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, 2, winetemp, testpath);
1989     switch(ret) {
1990         case S_OK: /* winvista */
1991             ok(!strncmp(appdata, testpath, strlen(appdata)),
1992                 "expected %s to start with %s\n", testpath, appdata);
1993             ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1994                 "expected %s to end with %s\n", testpath, winetemp);
1995             break;
1996         case E_INVALIDARG: /* winxp, win2k3 */
1997             break;
1998         default:
1999             ok(0, "expected S_OK or E_INVALIDARG, got  %x\n", ret);
2000     }
2001
2002     /* test fifth parameter */
2003     testpath[0] = '\0';
2004     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, NULL, testpath);
2005     ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2006     ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2007
2008     testpath[0] = '\0';
2009     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "", testpath);
2010     ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2011     ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2012
2013     testpath[0] = '\0';
2014     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "\\", testpath);
2015     ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2016     ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2017
2018     for(i=0; i< MAX_PATH; i++)
2019         toolongpath[i] = '0' + i % 10;
2020     toolongpath[MAX_PATH] = '\0';
2021     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, toolongpath, testpath);
2022     ok(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) == ret,
2023         "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), ret);
2024
2025     testpath[0] = '\0';
2026     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wine, NULL);
2027     ok((S_OK == ret) || (E_INVALIDARG == ret), "expected S_OK or E_INVALIDARG, got %x\n", ret);
2028
2029     /* test a not existing path */
2030     testpath[0] = '\0';
2031     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
2032     ok(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == ret,
2033         "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), ret);
2034
2035     /* create a directory inside a not existing directory */
2036     testpath[0] = '\0';
2037     ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_CREATE | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
2038     ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2039     ok(!strncmp(appdata, testpath, strlen(appdata)),
2040         "expected %s to start with %s\n", testpath, appdata);
2041     ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
2042         "expected %s to end with %s\n", testpath, winetemp);
2043     dwret = GetFileAttributes(testpath);
2044     ok(FILE_ATTRIBUTE_DIRECTORY | dwret, "expected %x to contain FILE_ATTRIBUTE_DIRECTORY\n", dwret);
2045
2046     /* cleanup */
2047     sprintf(testpath, "%s\\%s", appdata, winetemp);
2048     RemoveDirectoryA(testpath);
2049     sprintf(testpath, "%s\\%s", appdata, wine);
2050     RemoveDirectoryA(testpath);
2051 }
2052
2053 static void test_LocalizedNames(void)
2054 {
2055     static char cCurrDirA[MAX_PATH];
2056     WCHAR cCurrDirW[MAX_PATH], tempbufW[25];
2057     IShellFolder *IDesktopFolder, *testIShellFolder;
2058     ITEMIDLIST *newPIDL;
2059     int len;
2060     HRESULT hr;
2061     static char resourcefile[MAX_PATH];
2062     DWORD res;
2063     HANDLE file;
2064     STRRET strret;
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     ok(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        "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             ret = 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             ret = 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         hres = 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         hres = 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
2788     /* Generate ShellItems for the files */
2789     ZeroMemory(&psi, sizeof(IShellItem*)*9);
2790     failed = FALSE;
2791     for(i = 0; i < 9; i++)
2792     {
2793         LPITEMIDLIST pidl_testfile = NULL;
2794
2795         hr = IShellFolder_ParseDisplayName(psf_current, NULL, NULL, (LPWSTR)filesW[i],
2796                                            NULL, &pidl_testfile, NULL);
2797         ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2798         if(SUCCEEDED(hr))
2799         {
2800             hr = pSHCreateShellItem(NULL, NULL, pidl_testfile, &psi[i]);
2801             ok(hr == S_OK, "Got 0x%08x\n", hr);
2802             pILFree(pidl_testfile);
2803         }
2804         if(FAILED(hr)) failed = TRUE;
2805     }
2806     if(failed)
2807     {
2808         skip("Failed to create all shellitems.\n");
2809         goto cleanup;
2810     }
2811
2812     /* Generate ShellItems for the folders */
2813     hr = IShellItem_GetParent(psi[0], &psi_a);
2814     ok(hr == S_OK, "Got 0x%08x\n", hr);
2815     if(FAILED(hr)) failed = TRUE;
2816     hr = IShellItem_GetParent(psi[3], &psi_b);
2817     ok(hr == S_OK, "Got 0x%08x\n", hr);
2818     if(FAILED(hr)) failed = TRUE;
2819     hr = IShellItem_GetParent(psi[6], &psi_c);
2820     ok(hr == S_OK, "Got 0x%08x\n", hr);
2821     if(FAILED(hr)) failed = TRUE;
2822
2823     if(failed)
2824     {
2825         skip("Failed to create shellitems.\n");
2826         goto cleanup;
2827     }
2828
2829     if(0)
2830     {
2831         /* Crashes on native (win7, winxp) */
2832         hr = IShellItem_Compare(psi_a, NULL, 0, NULL);
2833         hr = IShellItem_Compare(psi_a, psi_b, 0, NULL);
2834         hr = IShellItem_Compare(psi_a, NULL, 0, &order);
2835     }
2836
2837     /* Basics */
2838     for(i = 0; i < 9; i++)
2839     {
2840         hr = IShellItem_Compare(psi[i], psi[i], SICHINT_DISPLAY, &order);
2841         ok(hr == S_OK, "Got 0x%08x\n", hr);
2842         ok(order == 0, "Got order %d\n", order);
2843         hr = IShellItem_Compare(psi[i], psi[i], SICHINT_CANONICAL, &order);
2844         ok(hr == S_OK, "Got 0x%08x\n", hr);
2845         ok(order == 0, "Got order %d\n", order);
2846         hr = IShellItem_Compare(psi[i], psi[i], SICHINT_ALLFIELDS, &order);
2847         ok(hr == S_OK, "Got 0x%08x\n", hr);
2848         ok(order == 0, "Got order %d\n", order);
2849     }
2850
2851     /* Order */
2852     /* a\b:a\a , a\b:a\c, a\b:a\b */
2853     hr = IShellItem_Compare(psi[1], psi[0], SICHINT_DISPLAY, &order);
2854     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2855     ok(order == 1, "Got order %d\n", order);
2856     hr = IShellItem_Compare(psi[1], psi[2], SICHINT_DISPLAY, &order);
2857     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2858     ok(order == -1, "Got order %d\n", order);
2859     hr = IShellItem_Compare(psi[1], psi[1], SICHINT_DISPLAY, &order);
2860     ok(hr == S_OK, "Got 0x%08x\n", hr);
2861     ok(order == 0, "Got order %d\n", order);
2862
2863     /* b\b:a\b, b\b:c\b, b\b:c\b */
2864     hr = IShellItem_Compare(psi[4], psi[1], SICHINT_DISPLAY, &order);
2865     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2866     ok(order == 1, "Got order %d\n", order);
2867     hr = IShellItem_Compare(psi[4], psi[7], SICHINT_DISPLAY, &order);
2868     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2869     ok(order == -1, "Got order %d\n", order);
2870     hr = IShellItem_Compare(psi[4], psi[4], SICHINT_DISPLAY, &order);
2871     ok(hr == S_OK, "Got 0x%08x\n", hr);
2872     ok(order == 0, "Got order %d\n", order);
2873
2874     /* b:a\a, b:a\c, b:a\b */
2875     hr = IShellItem_Compare(psi_b, psi[0], SICHINT_DISPLAY, &order);
2876     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2877     todo_wine ok(order == 1, "Got order %d\n", order);
2878     hr = IShellItem_Compare(psi_b, psi[2], SICHINT_DISPLAY, &order);
2879     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2880     todo_wine ok(order == 1, "Got order %d\n", order);
2881     hr = IShellItem_Compare(psi_b, psi[1], SICHINT_DISPLAY, &order);
2882     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2883     todo_wine ok(order == 1, "Got order %d\n", order);
2884
2885     /* b:c\a, b:c\c, b:c\b */
2886     hr = IShellItem_Compare(psi_b, psi[6], SICHINT_DISPLAY, &order);
2887     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2888     ok(order == -1, "Got order %d\n", order);
2889     hr = IShellItem_Compare(psi_b, psi[8], SICHINT_DISPLAY, &order);
2890     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2891     ok(order == -1, "Got order %d\n", order);
2892     hr = IShellItem_Compare(psi_b, psi[7], SICHINT_DISPLAY, &order);
2893     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2894     ok(order == -1, "Got order %d\n", order);
2895
2896     /* a\b:a\a , a\b:a\c, a\b:a\b */
2897     hr = IShellItem_Compare(psi[1], psi[0], SICHINT_CANONICAL, &order);
2898     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2899     ok(order == 1, "Got order %d\n", order);
2900     hr = IShellItem_Compare(psi[1], psi[2], SICHINT_CANONICAL, &order);
2901     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2902     ok(order == -1, "Got order %d\n", order);
2903     hr = IShellItem_Compare(psi[1], psi[1], SICHINT_CANONICAL, &order);
2904     ok(hr == S_OK, "Got 0x%08x\n", hr);
2905     ok(order == 0, "Got order %d\n", order);
2906
2907     /* b\b:a\b, b\b:c\b, b\b:c\b */
2908     hr = IShellItem_Compare(psi[4], psi[1], SICHINT_CANONICAL, &order);
2909     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2910     ok(order == 1, "Got order %d\n", order);
2911     hr = IShellItem_Compare(psi[4], psi[7], SICHINT_CANONICAL, &order);
2912     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2913     ok(order == -1, "Got order %d\n", order);
2914     hr = IShellItem_Compare(psi[4], psi[4], SICHINT_CANONICAL, &order);
2915     ok(hr == S_OK, "Got 0x%08x\n", hr);
2916     ok(order == 0, "Got order %d\n", order);
2917
2918     /* b:a\a, b:a\c, b:a\b */
2919     hr = IShellItem_Compare(psi_b, psi[0], SICHINT_CANONICAL, &order);
2920     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2921     todo_wine ok(order == 1, "Got order %d\n", order);
2922     hr = IShellItem_Compare(psi_b, psi[2], SICHINT_CANONICAL, &order);
2923     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2924     todo_wine ok(order == 1, "Got order %d\n", order);
2925     hr = IShellItem_Compare(psi_b, psi[1], SICHINT_CANONICAL, &order);
2926     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2927     todo_wine ok(order == 1, "Got order %d\n", order);
2928
2929     /* b:c\a, b:c\c, b:c\b */
2930     hr = IShellItem_Compare(psi_b, psi[6], SICHINT_CANONICAL, &order);
2931     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2932     ok(order == -1, "Got order %d\n", order);
2933     hr = IShellItem_Compare(psi_b, psi[8], SICHINT_CANONICAL, &order);
2934     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2935     ok(order == -1, "Got order %d\n", order);
2936     hr = IShellItem_Compare(psi_b, psi[7], SICHINT_CANONICAL, &order);
2937     ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2938     ok(order == -1, "Got order %d\n", order);
2939
2940 cleanup:
2941     IShellFolder_Release(psf_current);
2942
2943     DeleteFileA(".\\a\\a");
2944     DeleteFileA(".\\a\\b");
2945     DeleteFileA(".\\a\\c");
2946     DeleteFileA(".\\b\\a");
2947     DeleteFileA(".\\b\\b");
2948     DeleteFileA(".\\b\\c");
2949     DeleteFileA(".\\c\\a");
2950     DeleteFileA(".\\c\\b");
2951     DeleteFileA(".\\c\\c");
2952     RemoveDirectoryA(".\\a");
2953     RemoveDirectoryA(".\\b");
2954     RemoveDirectoryA(".\\c");
2955
2956     if(psi_a) IShellItem_Release(psi_a);
2957     if(psi_b) IShellItem_Release(psi_b);
2958     if(psi_c) IShellItem_Release(psi_c);
2959
2960     for(i = 0; i < 9; i++)
2961         if(psi[i]) IShellItem_Release(psi[i]);
2962 }
2963
2964 /**************************************************************/
2965 /* IUnknown implementation for counting QueryInterface calls. */
2966 typedef struct {
2967     const IUnknownVtbl *lpVtbl;
2968     struct if_count {
2969         REFIID id;
2970         LONG count;
2971     } *ifaces;
2972     LONG unknown;
2973 } IUnknownImpl;
2974
2975 static HRESULT WINAPI unk_fnQueryInterface(IUnknown *iunk, REFIID riid, void** punk)
2976 {
2977     IUnknownImpl *This = (IUnknownImpl*)iunk;
2978     UINT i, found;
2979     for(i = found = 0; This->ifaces[i].id != NULL; i++)
2980     {
2981         if(IsEqualIID(This->ifaces[i].id, riid))
2982         {
2983             This->ifaces[i].count++;
2984             found = 1;
2985             break;
2986         }
2987     }
2988     if(!found)
2989         This->unknown++;
2990     return E_NOINTERFACE;
2991 }
2992
2993 static ULONG WINAPI unk_fnAddRef(IUnknown *iunk)
2994 {
2995     return 2;
2996 }
2997
2998 static ULONG WINAPI unk_fnRelease(IUnknown *iunk)
2999 {
3000     return 1;
3001 }
3002
3003 static const IUnknownVtbl vt_IUnknown = {
3004     unk_fnQueryInterface,
3005     unk_fnAddRef,
3006     unk_fnRelease
3007 };
3008
3009 static void test_SHGetIDListFromObject(void)
3010 {
3011     IUnknownImpl *punkimpl;
3012     IShellFolder *psfdesktop;
3013     IShellView *psv;
3014     LPITEMIDLIST pidl, pidl_desktop;
3015     HRESULT hres;
3016     UINT i;
3017     struct if_count ifaces[] =
3018         { {&IID_IPersistIDList, 0},
3019           {&IID_IPersistFolder2, 0},
3020           {&IID_IDataObject, 0},
3021           {&IID_IParentAndItem, 0},
3022           {&IID_IFolderView, 0},
3023           {NULL, 0} };
3024
3025     if(!pSHGetIDListFromObject)
3026     {
3027         win_skip("SHGetIDListFromObject missing.\n");
3028         return;
3029     }
3030
3031     ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
3032
3033     if(0)
3034     {
3035         /* Crashes native */
3036         pSHGetIDListFromObject(NULL, NULL);
3037         pSHGetIDListFromObject((void*)0xDEADBEEF, NULL);
3038     }
3039
3040     hres = pSHGetIDListFromObject(NULL, &pidl);
3041     ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3042
3043     punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
3044     punkimpl->lpVtbl = &vt_IUnknown;
3045     punkimpl->ifaces = ifaces;
3046     punkimpl->unknown = 0;
3047
3048     hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
3049     ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3050     ok(ifaces[0].count, "interface not requested.\n");
3051     ok(ifaces[1].count, "interface not requested.\n");
3052     ok(ifaces[2].count, "interface not requested.\n");
3053     todo_wine
3054         ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3055            "interface not requested.\n");
3056     ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3057        "interface not requested.\n");
3058
3059     ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3060     HeapFree(GetProcessHeap(), 0, punkimpl);
3061
3062     pidl_desktop = NULL;
3063     pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3064     ok(pidl_desktop != NULL, "Failed to get desktop pidl.\n");
3065
3066     SHGetDesktopFolder(&psfdesktop);
3067
3068     /* Test IShellItem */
3069     if(pSHCreateShellItem)
3070     {
3071         IShellItem *shellitem;
3072         hres = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
3073         ok(hres == S_OK, "got 0x%08x\n", hres);
3074         if(SUCCEEDED(hres))
3075         {
3076             hres = pSHGetIDListFromObject((IUnknown*)shellitem, &pidl);
3077             ok(hres == S_OK, "got 0x%08x\n", hres);
3078             if(SUCCEEDED(hres))
3079             {
3080                 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3081                 pILFree(pidl);
3082             }
3083             IShellItem_Release(shellitem);
3084         }
3085     }
3086     else
3087         skip("no SHCreateShellItem.\n");
3088
3089     /* Test IShellFolder */
3090     hres = pSHGetIDListFromObject((IUnknown*)psfdesktop, &pidl);
3091     ok(hres == S_OK, "got 0x%08x\n", hres);
3092     if(SUCCEEDED(hres))
3093     {
3094         ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3095         pILFree(pidl);
3096     }
3097
3098     hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
3099     ok(hres == S_OK, "got 0x%08x\n", hres);
3100     if(SUCCEEDED(hres))
3101     {
3102         IEnumIDList *peidl;
3103         IDataObject *pdo;
3104         SHCONTF enum_flags;
3105
3106         /* Test IFolderView */
3107         hres = pSHGetIDListFromObject((IUnknown*)psv, &pidl);
3108         ok(hres == S_OK, "got 0x%08x\n", hres);
3109         if(SUCCEEDED(hres))
3110         {
3111             ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3112             pILFree(pidl);
3113         }
3114
3115         /* Test IDataObject */
3116         enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3117         hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
3118         ok(hres == S_OK, "got 0x%08x\n", hres);
3119         if(SUCCEEDED(hres))
3120         {
3121             LPITEMIDLIST apidl[5];
3122             UINT count = 0;
3123             for(count = 0; count < 5; count++)
3124                 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3125                     break;
3126
3127             if(count)
3128             {
3129                 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
3130                                                   &IID_IDataObject, NULL, (void**)&pdo);
3131                 ok(hres == S_OK, "got 0x%08x\n", hres);
3132                 if(SUCCEEDED(hres))
3133                 {
3134                     pidl = (void*)0xDEADBEEF;
3135                     hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3136                     ok(hres == S_OK, "got 0x%08x\n", hres);
3137                     ok(pidl != NULL, "pidl is NULL.\n");
3138                     ok(ILIsEqual(pidl, apidl[0]), "pidl not equal.\n");
3139                     pILFree(pidl);
3140
3141                     IDataObject_Release(pdo);
3142                 }
3143             }
3144             else
3145                 skip("No files found - skipping single-file test.\n");
3146
3147             if(count > 1)
3148             {
3149                 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
3150                                                   &IID_IDataObject, NULL, (void**)&pdo);
3151                 ok(hres == S_OK, "got 0x%08x\n", hres);
3152                 if(SUCCEEDED(hres))
3153                 {
3154                     pidl = (void*)0xDEADBEEF;
3155                     hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3156                     ok(hres == E_NOINTERFACE || hres == E_FAIL /*Vista*/,
3157                        "got 0x%08x\n", hres);
3158                     ok(pidl == NULL, "pidl is not NULL.\n");
3159
3160                     IDataObject_Release(pdo);
3161                 }
3162             }
3163             else
3164                 skip("zero or one file found - skipping multi-file test.\n");
3165
3166             for(i = 0; i < count; i++)
3167                 pILFree(apidl[i]);
3168
3169             IEnumIDList_Release(peidl);
3170         }
3171
3172         IShellView_Release(psv);
3173     }
3174
3175     IShellFolder_Release(psfdesktop);
3176     pILFree(pidl_desktop);
3177 }
3178
3179 static void test_SHGetItemFromObject(void)
3180 {
3181     IUnknownImpl *punkimpl;
3182     IShellFolder *psfdesktop;
3183     LPITEMIDLIST pidl;
3184     IShellItem *psi;
3185     IUnknown *punk;
3186     HRESULT hres;
3187     struct if_count ifaces[] =
3188         { {&IID_IPersistIDList, 0},
3189           {&IID_IPersistFolder2, 0},
3190           {&IID_IDataObject, 0},
3191           {&IID_IParentAndItem, 0},
3192           {&IID_IFolderView, 0},
3193           {NULL, 0} };
3194
3195     if(!pSHGetItemFromObject)
3196     {
3197         skip("No SHGetItemFromObject.\n");
3198         return;
3199     }
3200
3201     SHGetDesktopFolder(&psfdesktop);
3202
3203     if(0)
3204     {
3205         /* Crashes with Windows 7 */
3206         hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IUnknown, NULL);
3207         hres = pSHGetItemFromObject(NULL, &IID_IUnknown, NULL);
3208         hres = pSHGetItemFromObject((IUnknown*)psfdesktop, NULL, (void**)&punk);
3209     }
3210
3211     hres = pSHGetItemFromObject(NULL, &IID_IUnknown, (void**)&punk);
3212     ok(hres == E_NOINTERFACE, "Got 0x%08x\n", hres);
3213
3214     punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
3215     punkimpl->lpVtbl = &vt_IUnknown;
3216     punkimpl->ifaces = ifaces;
3217     punkimpl->unknown = 0;
3218
3219     /* The same as SHGetIDListFromObject */
3220     hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
3221     ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3222     ok(ifaces[0].count, "interface not requested.\n");
3223     ok(ifaces[1].count, "interface not requested.\n");
3224     ok(ifaces[2].count, "interface not requested.\n");
3225     todo_wine
3226         ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3227            "interface not requested.\n");
3228     ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3229        "interface not requested.\n");
3230
3231     ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3232     HeapFree(GetProcessHeap(), 0, punkimpl);
3233
3234     /* Test IShellItem */
3235     hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IShellItem, (void**)&psi);
3236     ok(hres == S_OK, "Got 0x%08x\n", hres);
3237     if(SUCCEEDED(hres))
3238     {
3239         IShellItem *psi2;
3240         hres = pSHGetItemFromObject((IUnknown*)psi, &IID_IShellItem, (void**)&psi2);
3241         ok(hres == S_OK, "Got 0x%08x\n", hres);
3242         if(SUCCEEDED(hres))
3243         {
3244             todo_wine
3245                 ok(psi == psi2, "Different instances (%p != %p).\n", psi, psi2);
3246             IShellItem_Release(psi2);
3247         }
3248         IShellItem_Release(psi);
3249     }
3250
3251     IShellFolder_Release(psfdesktop);
3252 }
3253
3254 static void test_SHCreateShellItemArray(void)
3255 {
3256     IShellFolder *pdesktopsf, *psf;
3257     IShellItemArray *psia;
3258     IEnumIDList *peidl;
3259     HRESULT hr;
3260     WCHAR cTestDirW[MAX_PATH];
3261     LPITEMIDLIST pidl_testdir, pidl;
3262     static const WCHAR testdirW[] = {'t','e','s','t','d','i','r',0};
3263
3264     if(!pSHCreateShellItemArray) {
3265         skip("No pSHCreateShellItemArray!\n");
3266         return;
3267     }
3268
3269     ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
3270
3271     if(0)
3272     {
3273         /* Crashes under native */
3274         pSHCreateShellItemArray(NULL, NULL, 0, NULL, NULL);
3275         pSHCreateShellItemArray(NULL, NULL, 1, NULL, NULL);
3276         pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, NULL);
3277         pSHCreateShellItemArray(pidl, NULL, 0, NULL, NULL);
3278     }
3279
3280     hr = pSHCreateShellItemArray(NULL, NULL, 0, NULL, &psia);
3281     ok(hr == E_POINTER, "got 0x%08x\n", hr);
3282
3283     SHGetDesktopFolder(&pdesktopsf);
3284     hr = pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, &psia);
3285     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3286
3287     hr = pSHCreateShellItemArray(NULL, pdesktopsf, 1, NULL, &psia);
3288     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3289
3290     pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
3291     hr = pSHCreateShellItemArray(pidl, NULL, 0, NULL, &psia);
3292     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3293     pILFree(pidl);
3294
3295     GetCurrentDirectoryW(MAX_PATH, cTestDirW);
3296     myPathAddBackslashW(cTestDirW);
3297     lstrcatW(cTestDirW, testdirW);
3298
3299     CreateFilesFolders();
3300
3301     hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, cTestDirW, NULL, &pidl_testdir, 0);
3302     ok(hr == S_OK, "got 0x%08x\n", hr);
3303     if(SUCCEEDED(hr))
3304     {
3305         hr = IShellFolder_BindToObject(pdesktopsf, pidl_testdir, NULL, (REFIID)&IID_IShellFolder,
3306                                        (void**)&psf);
3307         ok(hr == S_OK, "Got 0x%08x\n", hr);
3308     }
3309     IShellFolder_Release(pdesktopsf);
3310
3311     if(FAILED(hr))
3312     {
3313         skip("Failed to set up environment for SHCreateShellItemArray tests.\n");
3314         pILFree(pidl_testdir);
3315         Cleanup();
3316         return;
3317     }
3318
3319     hr = IShellFolder_EnumObjects(psf, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &peidl);
3320     ok(hr == S_OK, "Got %08x\n", hr);
3321     if(SUCCEEDED(hr))
3322     {
3323         LPITEMIDLIST apidl[5];
3324         UINT done, numitems, i;
3325
3326         for(done = 0; done < 5; done++)
3327             if(IEnumIDList_Next(peidl, 1, &apidl[done], NULL) != S_OK)
3328                 break;
3329         ok(done == 5, "Got %d pidls\n", done);
3330         IEnumIDList_Release(peidl);
3331
3332         /* Create a ShellItemArray */
3333         hr = pSHCreateShellItemArray(NULL, psf, done, (LPCITEMIDLIST*)apidl, &psia);
3334         ok(hr == S_OK, "Got 0x%08x\n", hr);
3335         if(SUCCEEDED(hr))
3336         {
3337             IShellItem *psi;
3338
3339             if(0)
3340             {
3341                 /* Crashes in Windows 7 */
3342                 hr = IShellItemArray_GetCount(psia, NULL);
3343             }
3344
3345             IShellItemArray_GetCount(psia, &numitems);
3346             ok(numitems == done, "Got %d, expected %d\n", numitems, done);
3347
3348             hr = IShellItemArray_GetItemAt(psia, numitems, &psi);
3349             ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3350
3351             /* Compare all the items */
3352             for(i = 0; i < numitems; i++)
3353             {
3354                 LPITEMIDLIST pidl_abs;
3355                 pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3356
3357                 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3358                 ok(hr == S_OK, "(%d) Failed with 0x%08x\n", i, hr);
3359                 if(SUCCEEDED(hr))
3360                 {
3361                     hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3362                     ok(hr == S_OK, "Got 0x%08x\n", hr);
3363                     if(SUCCEEDED(hr))
3364                     {
3365                         ok(ILIsEqual(pidl_abs, pidl), "Pidl not equal.\n");
3366                         pILFree(pidl);
3367                     }
3368                     IShellItem_Release(psi);
3369                 }
3370                 pILFree(pidl_abs);
3371             }
3372             for(i = 0; i < done; i++)
3373                 pILFree(apidl[i]);
3374             IShellItemArray_Release(psia);
3375         }
3376     }
3377
3378     /* SHCreateShellItemArrayFromShellItem */
3379     if(pSHCreateShellItemArrayFromShellItem)
3380     {
3381         IShellItem *psi;
3382
3383         if(0)
3384         {
3385             /* Crashes under Windows 7 */
3386             hr = pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, NULL);
3387             hr = pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, (void**)&psia);
3388             hr = pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, NULL);
3389         }
3390
3391         hr = pSHCreateItemFromIDList(pidl_testdir, &IID_IShellItem, (void**)&psi);
3392         ok(hr == S_OK, "Got 0x%08x\n", hr);
3393         if(SUCCEEDED(hr))
3394         {
3395             hr = pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, (void**)&psia);
3396             ok(hr == S_OK, "Got 0x%08x\n", hr);
3397             if(SUCCEEDED(hr))
3398             {
3399                 IShellItem *psi2;
3400                 UINT count;
3401                 hr = IShellItemArray_GetCount(psia, &count);
3402                 ok(hr == S_OK, "Got 0x%08x\n", hr);
3403                 ok(count == 1, "Got count %d\n", count);
3404                 hr = IShellItemArray_GetItemAt(psia, 0, &psi2);
3405                 ok(hr == S_OK, "Got 0x%08x\n", hr);
3406                 todo_wine
3407                     ok(psi != psi2, "ShellItems are of the same instance.\n");
3408                 if(SUCCEEDED(hr))
3409                 {
3410                     LPITEMIDLIST pidl1, pidl2;
3411                     hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl1);
3412                     ok(hr == S_OK, "Got 0x%08x\n", hr);
3413                     ok(pidl1 != NULL, "pidl1 was null.\n");
3414                     hr = pSHGetIDListFromObject((IUnknown*)psi2, &pidl2);
3415                     ok(hr == S_OK, "Got 0x%08x\n", hr);
3416                     ok(pidl2 != NULL, "pidl2 was null.\n");
3417                     ok(ILIsEqual(pidl1, pidl2), "pidls not equal.\n");
3418                     pILFree(pidl1);
3419                     pILFree(pidl2);
3420                     IShellItem_Release(psi2);
3421                 }
3422                 hr = IShellItemArray_GetItemAt(psia, 1, &psi2);
3423                 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3424                 IShellItemArray_Release(psia);
3425             }
3426             IShellItem_Release(psi);
3427         }
3428     }
3429     else
3430         skip("No SHCreateShellItemArrayFromShellItem.\n");
3431
3432     if(pSHCreateShellItemArrayFromDataObject)
3433     {
3434         IShellView *psv;
3435
3436         if(0)
3437         {
3438             /* Crashes under Windows 7 */
3439             hr = pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, NULL);
3440         }
3441         hr = pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, (void**)&psia);
3442         ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3443
3444         hr = IShellFolder_CreateViewObject(psf, NULL, &IID_IShellView, (void**)&psv);
3445         ok(hr == S_OK, "got 0x%08x\n", hr);
3446         if(SUCCEEDED(hr))
3447         {
3448             IEnumIDList *peidl;
3449             IDataObject *pdo;
3450             SHCONTF enum_flags;
3451
3452             enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3453             hr = IShellFolder_EnumObjects(psf, NULL, enum_flags, &peidl);
3454             ok(hr == S_OK, "got 0x%08x\n", hr);
3455             if(SUCCEEDED(hr))
3456             {
3457                 LPITEMIDLIST apidl[5];
3458                 UINT count, i;
3459
3460                 for(count = 0; count < 5; count++)
3461                     if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3462                         break;
3463                 ok(count == 5, "Got %d\n", count);
3464
3465                 if(count)
3466                 {
3467                     hr = IShellFolder_GetUIObjectOf(psf, NULL, count, (LPCITEMIDLIST*)apidl,
3468                                                     &IID_IDataObject, NULL, (void**)&pdo);
3469                     ok(hr == S_OK, "Got 0x%08x\n", hr);
3470                     if(SUCCEEDED(hr))
3471                     {
3472                         hr = pSHCreateShellItemArrayFromDataObject(pdo, &IID_IShellItemArray,
3473                                                                    (void**)&psia);
3474                         ok(hr == S_OK, "Got 0x%08x\n", hr);
3475                         if(SUCCEEDED(hr))
3476                         {
3477                             UINT count_sia, i;
3478                             hr = IShellItemArray_GetCount(psia, &count_sia);
3479                             ok(count_sia == count, "Counts differ (%d, %d)\n", count, count_sia);
3480                             for(i = 0; i < count_sia; i++)
3481                             {
3482                                 LPITEMIDLIST pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3483                                 IShellItem *psi;
3484                                 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3485                                 ok(hr == S_OK, "Got 0x%08x\n", hr);
3486                                 if(SUCCEEDED(hr))
3487                                 {
3488                                     LPITEMIDLIST pidl;
3489                                     hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3490                                     ok(hr == S_OK, "Got 0x%08x\n", hr);
3491                                     ok(pidl != NULL, "pidl as NULL.\n");
3492                                     ok(ILIsEqual(pidl, pidl_abs), "pidls differ.\n");
3493                                     pILFree(pidl);
3494                                     IShellItem_Release(psi);
3495                                 }
3496                                 pILFree(pidl_abs);
3497                             }
3498
3499                             IShellItemArray_Release(psia);
3500                         }
3501
3502                         IDataObject_Release(pdo);
3503                     }
3504                     for(i = 0; i < count; i++)
3505                         pILFree(apidl[i]);
3506                 }
3507                 else
3508                     skip("No files found - skipping test.\n");
3509
3510                 IEnumIDList_Release(peidl);
3511             }
3512             IShellView_Release(psv);
3513         }
3514     }
3515     else
3516         skip("No SHCreateShellItemArrayFromDataObject.\n");
3517
3518     IShellFolder_Release(psf);
3519     pILFree(pidl_testdir);
3520     Cleanup();
3521 }
3522
3523 static void test_ShellItemBindToHandler(void)
3524 {
3525     IShellItem *psi;
3526     LPITEMIDLIST pidl_desktop;
3527     HRESULT hr;
3528
3529     if(!pSHCreateShellItem)
3530     {
3531         skip("SHCreateShellItem missing.\n");
3532         return;
3533     }
3534
3535     hr = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3536     ok(hr == S_OK, "Got 0x%08x\n", hr);
3537     if(SUCCEEDED(hr))
3538     {
3539         hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
3540         ok(hr == S_OK, "Got 0x%08x\n", hr);
3541     }
3542     if(SUCCEEDED(hr))
3543     {
3544         IPersistFolder2 *ppf2;
3545         IUnknown *punk;
3546
3547         if(0)
3548         {
3549             /* Crashes under Windows 7 */
3550             hr = IShellItem_BindToHandler(psi, NULL, NULL, NULL, NULL);
3551             hr = IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, NULL);
3552         }
3553         hr = IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, (void**)&punk);
3554         ok(hr == MK_E_NOOBJECT, "Got 0x%08x\n", hr);
3555
3556         /* BHID_SFObject */
3557         hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IShellFolder, (void**)&punk);
3558         ok(hr == S_OK, "Got 0x%08x\n", hr);
3559         if(SUCCEEDED(hr)) IUnknown_Release(punk);
3560         hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IPersistFolder2, (void**)&ppf2);
3561         ok(hr == S_OK, "Got 0x%08x\n", hr);
3562         if(SUCCEEDED(hr))
3563         {
3564             LPITEMIDLIST pidl_tmp;
3565             hr = IPersistFolder2_GetCurFolder(ppf2, &pidl_tmp);
3566             ok(hr == S_OK, "Got 0x%08x\n", hr);
3567             if(SUCCEEDED(hr))
3568             {
3569                 ok(ILIsEqual(pidl_desktop, pidl_tmp), "Pidl not equal (%p, %p)\n", pidl_desktop, pidl_tmp);
3570                 pILFree(pidl_tmp);
3571             }
3572             IPersistFolder2_Release(ppf2);
3573         }
3574
3575         /* BHID_SFUIObject */
3576         hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IDataObject, (void**)&punk);
3577         ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3578         if(SUCCEEDED(hr)) IUnknown_Release(punk);
3579         hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IContextMenu, (void**)&punk);
3580         ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3581         if(SUCCEEDED(hr)) IUnknown_Release(punk);
3582
3583         /* BHID_DataObject */
3584         hr = IShellItem_BindToHandler(psi, NULL, &BHID_DataObject, &IID_IDataObject, (void**)&punk);
3585         ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3586         if(SUCCEEDED(hr)) IUnknown_Release(punk);
3587
3588         todo_wine
3589         {
3590             /* BHID_SFViewObject */
3591             hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellView, (void**)&punk);
3592             ok(hr == S_OK, "Got 0x%08x\n", hr);
3593             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3594             hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellFolderView, (void**)&punk);
3595             ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3596             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3597
3598             /* BHID_Storage */
3599             hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IStream, (void**)&punk);
3600             ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3601             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3602             hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IUnknown, (void**)&punk);
3603             ok(hr == S_OK, "Got 0x%08x\n", hr);
3604             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3605
3606             /* BHID_Stream */
3607             hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IStream, (void**)&punk);
3608             ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3609             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3610             hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IUnknown, (void**)&punk);
3611             ok(hr == S_OK, "Got 0x%08x\n", hr);
3612             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3613
3614             /* BHID_StorageEnum */
3615             hr = IShellItem_BindToHandler(psi, NULL, &BHID_StorageEnum, &IID_IEnumShellItems, (void**)&punk);
3616             ok(hr == S_OK, "Got 0x%08x\n", hr);
3617             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3618
3619             /* BHID_Transfer */
3620             hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_IUnknown, (void**)&punk);
3621             ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3622             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3623
3624             /* BHID_EnumItems */
3625             hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumItems, &IID_IEnumShellItems, (void**)&punk);
3626             ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3627             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3628
3629             /* BHID_Filter */
3630             hr = IShellItem_BindToHandler(psi, NULL, &BHID_Filter, &IID_IUnknown, (void**)&punk);
3631             ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3632             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3633
3634             /* BHID_LinkTargetItem */
3635             hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IShellItem, (void**)&punk);
3636             ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3637             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3638             hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IUnknown, (void**)&punk);
3639             ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3640             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3641
3642             /* BHID_PropertyStore */
3643             hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStore, (void**)&punk);
3644             ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3645             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3646             hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStoreFactory, (void**)&punk);
3647             ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3648             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3649
3650             /* BHID_ThumbnailHandler */
3651             hr = IShellItem_BindToHandler(psi, NULL, &BHID_ThumbnailHandler, &IID_IUnknown, (void**)&punk);
3652             ok(hr == E_INVALIDARG || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3653             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3654
3655             /* BHID_AssociationArray */
3656             hr = IShellItem_BindToHandler(psi, NULL, &BHID_AssociationArray, &IID_IQueryAssociations, (void**)&punk);
3657             ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3658             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3659
3660             /* BHID_EnumAssocHandlers */
3661             hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumAssocHandlers, &IID_IUnknown, (void**)&punk);
3662             ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3663             if(SUCCEEDED(hr)) IUnknown_Release(punk);
3664         }
3665
3666         IShellItem_Release(psi);
3667     }
3668     else
3669         skip("Failed to create ShellItem.\n");
3670
3671     pILFree(pidl_desktop);
3672 }
3673
3674 static void test_SHParseDisplayName(void)
3675 {
3676     LPITEMIDLIST pidl1, pidl2;
3677     IShellFolder *desktop;
3678     WCHAR dirW[MAX_PATH];
3679     WCHAR nameW[10];
3680     HRESULT hr;
3681     BOOL ret;
3682
3683     if (!pSHParseDisplayName)
3684     {
3685         win_skip("SHParseDisplayName isn't available\n");
3686         return;
3687     }
3688
3689 if (0)
3690 {
3691     /* crashes on native */
3692     hr = pSHParseDisplayName(NULL, NULL, NULL, 0, NULL);
3693     nameW[0] = 0;
3694     hr = pSHParseDisplayName(nameW, NULL, NULL, 0, NULL);
3695 }
3696
3697     pidl1 = (LPITEMIDLIST)0xdeadbeef;
3698     hr = pSHParseDisplayName(NULL, NULL, &pidl1, 0, NULL);
3699     ok(broken(hr == E_OUTOFMEMORY) /* < Vista */ ||
3700        hr == E_INVALIDARG, "failed %08x\n", hr);
3701     ok(pidl1 == 0, "expected null ptr, got %p\n", pidl1);
3702
3703     /* dummy name */
3704     nameW[0] = 0;
3705     hr = pSHParseDisplayName(nameW, NULL, &pidl1, 0, NULL);
3706     ok(hr == S_OK, "failed %08x\n", hr);
3707     hr = SHGetDesktopFolder(&desktop);
3708     ok(hr == S_OK, "failed %08x\n", hr);
3709     hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, nameW, NULL, &pidl2, NULL);
3710     ok(hr == S_OK, "failed %08x\n", hr);
3711     ret = pILIsEqual(pidl1, pidl2);
3712     ok(ret == TRUE, "expected equal idls\n");
3713     pILFree(pidl1);
3714     pILFree(pidl2);
3715
3716     /* with path */
3717     GetWindowsDirectoryW( dirW, MAX_PATH );
3718
3719     hr = pSHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
3720     ok(hr == S_OK, "failed %08x\n", hr);
3721     hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, dirW, NULL, &pidl2, NULL);
3722     ok(hr == S_OK, "failed %08x\n", hr);
3723
3724     ret = pILIsEqual(pidl1, pidl2);
3725     ok(ret == TRUE, "expected equal idls\n");
3726     pILFree(pidl1);
3727     pILFree(pidl2);
3728
3729     IShellFolder_Release(desktop);
3730 }
3731
3732 static void test_desktop_IPersist(void)
3733 {
3734     IShellFolder *desktop;
3735     IPersist *persist;
3736     IPersistFolder2 *ppf2;
3737     CLSID clsid;
3738     HRESULT hr;
3739
3740     hr = SHGetDesktopFolder(&desktop);
3741     ok(hr == S_OK, "failed %08x\n", hr);
3742
3743     hr = IShellFolder_QueryInterface(desktop, &IID_IPersist, (void**)&persist);
3744     ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* NT4, W9X */, "failed %08x\n", hr);
3745
3746     if (hr == S_OK)
3747     {
3748     if (0)
3749     {
3750         /* crashes on native */
3751         hr = IPersist_GetClassID(persist, NULL);
3752     }
3753         memset(&clsid, 0, sizeof(clsid));
3754         hr = IPersist_GetClassID(persist, &clsid);
3755         ok(hr == S_OK, "failed %08x\n", hr);
3756         ok(IsEqualIID(&CLSID_ShellDesktop, &clsid), "Expected CLSID_ShellDesktop\n");
3757         IPersist_Release(persist);
3758     }
3759
3760     hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder2, (void**)&ppf2);
3761     ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* pre-Vista */, "failed %08x\n", hr);
3762     if(SUCCEEDED(hr))
3763     {
3764         IPersistFolder *ppf;
3765         LPITEMIDLIST pidl;
3766         hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder, (void**)&ppf);
3767         ok(hr == S_OK, "IID_IPersistFolder2 without IID_IPersistFolder.\n");
3768         if(SUCCEEDED(hr))
3769             IPersistFolder_Release(ppf);
3770
3771         todo_wine {
3772             hr = IPersistFolder2_Initialize(ppf2, NULL);
3773             ok(hr == S_OK, "got %08x\n", hr);
3774         }
3775
3776         pidl = NULL;
3777         hr = IPersistFolder2_GetCurFolder(ppf2, &pidl);
3778         ok(hr == S_OK, "got %08x\n", hr);
3779         ok(pidl != NULL, "pidl was NULL.\n");
3780         if(SUCCEEDED(hr)) pILFree(pidl);
3781
3782         IPersistFolder2_Release(ppf2);
3783     }
3784
3785     IShellFolder_Release(desktop);
3786 }
3787
3788 static void test_GetUIObject(void)
3789 {
3790     IShellFolder *psf_desktop;
3791     IContextMenu *pcm;
3792     LPITEMIDLIST pidl;
3793     HRESULT hr;
3794     WCHAR path[MAX_PATH];
3795     const WCHAR filename[] =
3796         {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
3797
3798     if(!pSHBindToParent)
3799     {
3800         win_skip("SHBindToParent missing.\n");
3801         return;
3802     }
3803
3804     GetCurrentDirectoryW(MAX_PATH, path);
3805     if(!lstrlenW(path))
3806     {
3807         skip("GetCurrentDirectoryW returned an empty string.\n");
3808         return;
3809     }
3810     lstrcatW(path, filename);
3811     SHGetDesktopFolder(&psf_desktop);
3812
3813     CreateFilesFolders();
3814
3815     hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, path, NULL, &pidl, 0);
3816     ok(hr == S_OK || broken(hr == E_FAIL) /* WinME */, "Got 0x%08x\n", hr);
3817     if(SUCCEEDED(hr))
3818     {
3819         IShellFolder *psf;
3820         LPCITEMIDLIST pidl_child;
3821         hr = pSHBindToParent(pidl, &IID_IShellFolder, (void**)&psf, &pidl_child);
3822         ok(hr == S_OK, "Got 0x%08x\n", hr);
3823         if(SUCCEEDED(hr))
3824         {
3825             hr = IShellFolder_GetUIObjectOf(psf, NULL, 1, (LPCITEMIDLIST*)&pidl_child,
3826                                             &IID_IContextMenu, NULL, (void**)&pcm);
3827             ok(hr == S_OK, "Got 0x%08x\n", hr);
3828             if(SUCCEEDED(hr))
3829             {
3830                 HMENU hmenu = CreatePopupMenu();
3831                 INT max_id, max_id_check;
3832                 UINT count, i;
3833                 const int id_upper_limit = 32767;
3834                 hr = IContextMenu_QueryContextMenu(pcm, hmenu, 0, 0, id_upper_limit, CMF_NORMAL);
3835                 ok(SUCCEEDED(hr), "Got 0x%08x\n", hr);
3836                 max_id = HRESULT_CODE(hr) - 1; /* returns max_id + 1 */
3837                 ok(max_id <= id_upper_limit, "Got %d\n", max_id);
3838                 count = GetMenuItemCount(hmenu);
3839                 ok(count, "Got %d\n", count);
3840
3841                 max_id_check = 0;
3842                 for(i = 0; i < count; i++)
3843                 {
3844                     MENUITEMINFOA mii;
3845                     INT res;
3846                     ZeroMemory(&mii, sizeof(MENUITEMINFOA));
3847                     mii.cbSize = sizeof(MENUITEMINFOA);
3848                     mii.fMask = MIIM_ID | MIIM_FTYPE;
3849
3850                     SetLastError(0);
3851                     res = GetMenuItemInfoA(hmenu, i, TRUE, &mii);
3852                     ok(res, "Failed (last error: %d).\n", GetLastError());
3853
3854                     ok( (mii.wID <= id_upper_limit) || (mii.fType & MFT_SEPARATOR),
3855                         "Got non-separator ID out of range: %d (type: %x)\n", mii.wID, mii.fType);
3856                     if(!(mii.fType & MFT_SEPARATOR))
3857                         max_id_check = (mii.wID>max_id_check)?mii.wID:max_id_check;
3858                 }
3859                 ok((max_id_check == max_id) ||
3860                    (max_id_check == max_id-1 /* Win 7 */),
3861                    "Not equal (or near equal), got %d and %d\n", max_id_check, max_id);
3862
3863 #define is_win2k() (pSHGetFolderPathA && !pSHGetFolderPathAndSubDirA)
3864
3865                 if(count && !is_win2k())   /* Test is interactive on w2k, so skip */
3866                 {
3867                     CMINVOKECOMMANDINFO cmi;
3868                     ZeroMemory(&cmi, sizeof(CMINVOKECOMMANDINFO));
3869                     cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
3870
3871                     /* Attempt to execute a nonexistent command */
3872                     cmi.lpVerb = MAKEINTRESOURCEA(9999);
3873                     hr = IContextMenu_InvokeCommand(pcm, &cmi);
3874                     ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3875
3876                     cmi.lpVerb = "foobar_wine_test";
3877                     hr = IContextMenu_InvokeCommand(pcm, &cmi);
3878                     ok( (hr == E_INVALIDARG) || (hr == E_FAIL /* Win7 */) ||
3879                         (hr == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION) /* Vista */),
3880                         "Got 0x%08x\n", hr);
3881                 }
3882 #undef is_win2k
3883
3884                 DestroyMenu(hmenu);
3885                 IContextMenu_Release(pcm);
3886             }
3887             IShellFolder_Release(psf);
3888         }
3889         if(pILFree) pILFree(pidl);
3890     }
3891
3892     IShellFolder_Release(psf_desktop);
3893     Cleanup();
3894 }
3895
3896 #define verify_pidl(i,p) r_verify_pidl(__LINE__, i, p)
3897 static void r_verify_pidl(unsigned l, LPCITEMIDLIST pidl, const WCHAR *path)
3898 {
3899     LPCITEMIDLIST child;
3900     IShellFolder *parent;
3901     STRRET filename;
3902     HRESULT hr;
3903
3904     if(!pSHBindToParent){
3905         win_skip("SHBindToParent is not available, not performing full PIDL verification\n");
3906         if(path)
3907             ok_(__FILE__,l)(pidl != NULL, "Expected PIDL to be non-NULL\n");
3908         else
3909             ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
3910         return;
3911     }
3912
3913     if(path){
3914         if(!pidl){
3915             ok_(__FILE__,l)(0, "didn't get expected path (%s), instead: NULL\n", wine_dbgstr_w(path));
3916             return;
3917         }
3918
3919         hr = pSHBindToParent(pidl, &IID_IShellFolder, (LPVOID*)&parent, &child);
3920         ok_(__FILE__,l)(hr == S_OK, "SHBindToParent failed: 0x%08x\n", hr);
3921         if(FAILED(hr))
3922             return;
3923
3924         hr = IShellFolder_GetDisplayNameOf(parent, child, SHGDN_FORPARSING, &filename);
3925         ok_(__FILE__,l)(hr == S_OK, "GetDisplayNameOf failed: 0x%08x\n", hr);
3926         if(FAILED(hr)){
3927             IShellFolder_Release(parent);
3928             return;
3929         }
3930
3931         ok_(__FILE__,l)(filename.uType == STRRET_WSTR || filename.uType == STRRET_CSTR,
3932                 "Got unexpected string type: %d\n", filename.uType);
3933         if(filename.uType == STRRET_WSTR){
3934             ok_(__FILE__,l)(lstrcmpW(path, U(filename).pOleStr) == 0,
3935                     "didn't get expected path (%s), instead: %s\n",
3936                      wine_dbgstr_w(path), wine_dbgstr_w(U(filename).pOleStr));
3937         }else if(filename.uType == STRRET_CSTR){
3938             ok_(__FILE__,l)(strcmp_wa(path, U(filename).cStr) == 0,
3939                     "didn't get expected path (%s), instead: %s\n",
3940                      wine_dbgstr_w(path), U(filename).cStr);
3941         }
3942
3943         IShellFolder_Release(parent);
3944     }else
3945         ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
3946 }
3947
3948 static void test_SHSimpleIDListFromPath(void)
3949 {
3950     const WCHAR adirW[] = {'C',':','\\','s','i','d','l','f','p','d','i','r',0};
3951     const CHAR adirA[] = "C:\\sidlfpdir";
3952     BOOL br, is_unicode = !(GetVersion() & 0x80000000);
3953
3954     LPITEMIDLIST pidl = NULL;
3955
3956     if(!pSHSimpleIDListFromPathAW){
3957         win_skip("SHSimpleIDListFromPathAW not available\n");
3958         return;
3959     }
3960
3961     br = CreateDirectoryA(adirA, NULL);
3962     ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
3963
3964     if(is_unicode)
3965         pidl = pSHSimpleIDListFromPathAW(adirW);
3966     else
3967         pidl = pSHSimpleIDListFromPathAW(adirA);
3968     verify_pidl(pidl, adirW);
3969     pILFree(pidl);
3970
3971     br = RemoveDirectoryA(adirA);
3972     ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
3973
3974     if(is_unicode)
3975         pidl = pSHSimpleIDListFromPathAW(adirW);
3976     else
3977         pidl = pSHSimpleIDListFromPathAW(adirA);
3978     verify_pidl(pidl, adirW);
3979     pILFree(pidl);
3980 }
3981
3982 /* IFileSystemBindData impl */
3983 static HRESULT WINAPI fsbd_QueryInterface(IFileSystemBindData *fsbd,
3984         REFIID riid, void **ppv)
3985 {
3986     if(IsEqualIID(riid, &IID_IFileSystemBindData) ||
3987             IsEqualIID(riid, &IID_IUnknown)){
3988         *ppv = fsbd;
3989         return S_OK;
3990     }
3991     return E_NOINTERFACE;
3992 }
3993
3994 static ULONG WINAPI fsbd_AddRef(IFileSystemBindData *fsbd)
3995 {
3996     return 2;
3997 }
3998
3999 static ULONG WINAPI fsbd_Release(IFileSystemBindData *fsbd)
4000 {
4001     return 1;
4002 }
4003
4004 static HRESULT WINAPI fsbd_SetFindData(IFileSystemBindData *fsbd,
4005         const WIN32_FIND_DATAW *pfd)
4006 {
4007     ok(0, "SetFindData called\n");
4008     return E_NOTIMPL;
4009 }
4010
4011 static HRESULT WINAPI fsbd_GetFindData_nul(IFileSystemBindData *fsbd,
4012         WIN32_FIND_DATAW *pfd)
4013 {
4014     memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
4015     return S_OK;
4016 }
4017
4018 static HRESULT WINAPI fsbd_GetFindData_junk(IFileSystemBindData *fsbd,
4019         WIN32_FIND_DATAW *pfd)
4020 {
4021     memset(pfd, 0xdeadbeef, sizeof(WIN32_FIND_DATAW));
4022     return S_OK;
4023 }
4024
4025 static HRESULT WINAPI fsbd_GetFindData_invalid(IFileSystemBindData *fsbd,
4026         WIN32_FIND_DATAW *pfd)
4027 {
4028     memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
4029     *pfd->cFileName = 'a';
4030     *pfd->cAlternateFileName = 'a';
4031     return S_OK;
4032 }
4033
4034 static HRESULT WINAPI fsbd_GetFindData_valid(IFileSystemBindData *fsbd,
4035         WIN32_FIND_DATAW *pfd)
4036 {
4037     static const WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4038     HANDLE handle = FindFirstFileW(adirW, pfd);
4039     FindClose(handle);
4040     return S_OK;
4041 }
4042
4043 static HRESULT WINAPI fsbd_GetFindData_fail(IFileSystemBindData *fsbd,
4044         WIN32_FIND_DATAW *pfd)
4045 {
4046     return E_FAIL;
4047 }
4048
4049 static IFileSystemBindDataVtbl fsbdVtbl = {
4050     fsbd_QueryInterface,
4051     fsbd_AddRef,
4052     fsbd_Release,
4053     fsbd_SetFindData,
4054     NULL
4055 };
4056
4057 static IFileSystemBindData fsbd = { &fsbdVtbl };
4058
4059 static void test_ParseDisplayNamePBC(void)
4060 {
4061     WCHAR wFileSystemBindData[] =
4062         {'F','i','l','e',' ','S','y','s','t','e','m',' ','B','i','n','d',' ','D','a','t','a',0};
4063     WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4064     WCHAR afileW[] = {'C',':','\\','f','s','b','d','d','i','r','\\','f','i','l','e','.','t','x','t',0};
4065     WCHAR afile2W[] = {'C',':','\\','f','s','b','d','d','i','r','\\','s','\\','f','i','l','e','.','t','x','t',0};
4066     const HRESULT exp_err = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
4067
4068     IShellFolder *psf;
4069     IBindCtx *pbc;
4070     HRESULT hres;
4071     ITEMIDLIST *pidl;
4072
4073     /* Check if we support WCHAR functions */
4074     SetLastError(0xdeadbeef);
4075     lstrcmpiW(adirW, adirW);
4076     if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED){
4077         win_skip("Most W-calls are not implemented\n");
4078         return;
4079     }
4080
4081     hres = SHGetDesktopFolder(&psf);
4082     ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
4083     if(FAILED(hres)){
4084         win_skip("Failed to get IShellFolder, can't run tests\n");
4085         return;
4086     }
4087
4088     /* fails on unknown dir with no IBindCtx */
4089     hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, adirW, NULL, &pidl, NULL);
4090     ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4091             "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4092     hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, afileW, NULL, &pidl, NULL);
4093     ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4094             "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4095     hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, afile2W, NULL, &pidl, NULL);
4096     ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4097             "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4098
4099     /* fails on unknown dir with IBindCtx with no IFileSystemBindData */
4100     hres = CreateBindCtx(0, &pbc);
4101     ok(hres == S_OK, "CreateBindCtx failed: 0x%08x\n", hres);
4102
4103     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4104     ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4105             "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4106     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4107     ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4108             "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4109     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4110     ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4111             "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4112
4113     /* unknown dir with IBindCtx with IFileSystemBindData */
4114     hres = IBindCtx_RegisterObjectParam(pbc, wFileSystemBindData, (IUnknown*)&fsbd);
4115     ok(hres == S_OK, "RegisterObjectParam failed: 0x%08x\n", hres);
4116
4117     /* return E_FAIL from GetFindData */
4118     pidl = (ITEMIDLIST*)0xdeadbeef;
4119     fsbdVtbl.GetFindData = fsbd_GetFindData_fail;
4120     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4121     ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4122             "ParseDisplayName failed: 0x%08x\n", hres);
4123     if(SUCCEEDED(hres)){
4124         verify_pidl(pidl, adirW);
4125         ILFree(pidl);
4126     }
4127
4128     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4129     ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4130             "ParseDisplayName failed: 0x%08x\n", hres);
4131     if(SUCCEEDED(hres)){
4132         verify_pidl(pidl, afileW);
4133         ILFree(pidl);
4134     }
4135
4136     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4137     ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4138             "ParseDisplayName failed: 0x%08x\n", hres);
4139     if(SUCCEEDED(hres)){
4140         verify_pidl(pidl, afile2W);
4141         ILFree(pidl);
4142     }
4143
4144     /* set FIND_DATA struct to NULLs */
4145     pidl = (ITEMIDLIST*)0xdeadbeef;
4146     fsbdVtbl.GetFindData = fsbd_GetFindData_nul;
4147     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4148     ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4149             "ParseDisplayName failed: 0x%08x\n", hres);
4150     if(SUCCEEDED(hres)){
4151         verify_pidl(pidl, adirW);
4152         ILFree(pidl);
4153     }
4154
4155     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4156     ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4157             "ParseDisplayName failed: 0x%08x\n", hres);
4158     if(SUCCEEDED(hres)){
4159         verify_pidl(pidl, afileW);
4160         ILFree(pidl);
4161     }
4162
4163     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4164     ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4165             "ParseDisplayName failed: 0x%08x\n", hres);
4166     if(SUCCEEDED(hres)){
4167         verify_pidl(pidl, afile2W);
4168         ILFree(pidl);
4169     }
4170
4171     /* set FIND_DATA struct to junk */
4172     pidl = (ITEMIDLIST*)0xdeadbeef;
4173     fsbdVtbl.GetFindData = fsbd_GetFindData_junk;
4174     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4175     ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4176             "ParseDisplayName failed: 0x%08x\n", hres);
4177     if(SUCCEEDED(hres)){
4178         verify_pidl(pidl, adirW);
4179         ILFree(pidl);
4180     }
4181
4182     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4183     ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4184             "ParseDisplayName failed: 0x%08x\n", hres);
4185     if(SUCCEEDED(hres)){
4186         verify_pidl(pidl, afileW);
4187         ILFree(pidl);
4188     }
4189
4190     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4191     ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4192             "ParseDisplayName failed: 0x%08x\n", hres);
4193     if(SUCCEEDED(hres)){
4194         verify_pidl(pidl, afile2W);
4195         ILFree(pidl);
4196     }
4197
4198     /* set FIND_DATA struct to invalid data */
4199     pidl = (ITEMIDLIST*)0xdeadbeef;
4200     fsbdVtbl.GetFindData = fsbd_GetFindData_invalid;
4201     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4202     ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4203             "ParseDisplayName failed: 0x%08x\n", hres);
4204     if(SUCCEEDED(hres)){
4205         verify_pidl(pidl, adirW);
4206         ILFree(pidl);
4207     }
4208
4209     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4210     ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4211             "ParseDisplayName failed: 0x%08x\n", hres);
4212     if(SUCCEEDED(hres)){
4213         verify_pidl(pidl, afileW);
4214         ILFree(pidl);
4215     }
4216
4217     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4218     ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4219             "ParseDisplayName failed: 0x%08x\n", hres);
4220     if(SUCCEEDED(hres)){
4221         verify_pidl(pidl, afile2W);
4222         ILFree(pidl);
4223     }
4224
4225     /* set FIND_DATA struct to valid data */
4226     pidl = (ITEMIDLIST*)0xdeadbeef;
4227     fsbdVtbl.GetFindData = fsbd_GetFindData_valid;
4228     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4229     ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4230             "ParseDisplayName failed: 0x%08x\n", hres);
4231     if(SUCCEEDED(hres)){
4232         verify_pidl(pidl, adirW);
4233         ILFree(pidl);
4234     }
4235
4236     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4237     ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4238             "ParseDisplayName failed: 0x%08x\n", hres);
4239     if(SUCCEEDED(hres)){
4240         verify_pidl(pidl, afileW);
4241         ILFree(pidl);
4242     }
4243
4244     hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4245     ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4246             "ParseDisplayName failed: 0x%08x\n", hres);
4247     if(SUCCEEDED(hres)){
4248         verify_pidl(pidl, afile2W);
4249         ILFree(pidl);
4250     }
4251
4252     IBindCtx_Release(pbc);
4253     IShellFolder_Release(psf);
4254 }
4255
4256 static const CHAR testwindow_class[] = "testwindow";
4257 #define WM_USER_NOTIFY (WM_APP+1)
4258
4259 struct ChNotifyTest {
4260     const char id[256];
4261     const UINT notify_count;
4262     UINT missing_events;
4263     UINT signal;
4264     const char path_1[256];
4265     const char path_2[256];
4266 } chnotify_tests[] = {
4267     {"MKDIR", 1, 0, SHCNE_MKDIR, "C:\\shell32_cn_test\\test", ""},
4268     {"CREATE", 1, 0, SHCNE_CREATE, "C:\\shell32_cn_test\\test\\file.txt", ""},
4269     {"RMDIR", 1, 0, SHCNE_RMDIR, "C:\\shell32_cn_test\\test", ""},
4270 };
4271
4272 struct ChNotifyTest *exp_data;
4273
4274 static LRESULT CALLBACK testwindow_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
4275 {
4276     UINT signal = (UINT)lparam;
4277
4278     switch(msg){
4279     case WM_USER_NOTIFY:
4280         if(exp_data->missing_events > 0){
4281             WCHAR *path1, *path2;
4282             LPCITEMIDLIST *pidls = (LPCITEMIDLIST*)wparam;
4283
4284             ok(exp_data->signal == signal,
4285                     "%s: expected notification type %x, got: %x\n",
4286                     exp_data->id, exp_data->signal, signal);
4287
4288             trace("verifying pidls for: %s\n", exp_data->id);
4289             path1 = make_wstr(exp_data->path_1);
4290             path2 = make_wstr(exp_data->path_2);
4291             verify_pidl(pidls[0], path1);
4292             verify_pidl(pidls[1], path2);
4293             HeapFree(GetProcessHeap(), 0, path1);
4294             HeapFree(GetProcessHeap(), 0, path2);
4295
4296             exp_data->missing_events--;
4297         }else
4298             ok(0, "Didn't expect a WM_USER_NOTIFY message (event: %x)\n", signal);
4299         return 0;
4300     }
4301     return DefWindowProc(hwnd, msg, wparam, lparam);
4302 }
4303
4304 static void register_testwindow_class(void)
4305 {
4306     WNDCLASSEXA cls;
4307     ATOM ret;
4308
4309     ZeroMemory(&cls, sizeof(cls));
4310     cls.cbSize = sizeof(cls);
4311     cls.style = 0;
4312     cls.lpfnWndProc = testwindow_wndproc;
4313     cls.hInstance = GetModuleHandleA(NULL);
4314     cls.lpszClassName = testwindow_class;
4315
4316     SetLastError(0);
4317     ret = RegisterClassExA(&cls);
4318     ok(ret != 0, "RegisterClassExA failed: %d\n", GetLastError());
4319 }
4320
4321 /* SHCNF_FLUSH doesn't seem to work as advertised for SHCNF_PATHA, so we
4322  * have to poll repeatedly for the message to appear */
4323 static void do_events(void)
4324 {
4325     int c = 0;
4326     while (exp_data->missing_events && (c++ < 10)){
4327         MSG msg;
4328         while(PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)){
4329             TranslateMessage(&msg);
4330             DispatchMessageA(&msg);
4331         }
4332         if(exp_data->missing_events)
4333             Sleep(500);
4334     }
4335     trace("%s: took %d tries\n", exp_data->id, c);
4336 }
4337
4338 static void test_SHChangeNotify(void)
4339 {
4340     HWND wnd;
4341     ULONG notifyID, i;
4342     HRESULT hr;
4343     BOOL br, has_unicode;
4344     SHChangeNotifyEntry entries[1];
4345     const CHAR root_dirA[] = "C:\\shell32_cn_test";
4346     const WCHAR root_dirW[] = {'C',':','\\','s','h','e','l','l','3','2','_','c','n','_','t','e','s','t',0};
4347
4348     CreateDirectoryW(NULL, NULL);
4349     has_unicode = !(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED);
4350
4351     register_testwindow_class();
4352
4353     wnd = CreateWindowExA(0, testwindow_class, testwindow_class, 0,
4354             CW_USEDEFAULT, CW_USEDEFAULT, 130, 105,
4355             NULL, NULL, GetModuleHandleA(NULL), 0);
4356     ok(wnd != NULL, "Failed to make a window\n");
4357
4358     br = CreateDirectoryA(root_dirA, NULL);
4359     ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
4360
4361     entries[0].pidl = NULL;
4362     if(has_unicode)
4363         hr = SHILCreateFromPath(root_dirW, (LPITEMIDLIST*)&entries[0].pidl, 0);
4364     else
4365         hr = SHILCreateFromPath((LPCVOID)root_dirA, (LPITEMIDLIST*)&entries[0].pidl, 0);
4366     ok(hr == S_OK, "SHILCreateFromPath failed: 0x%08x\n", hr);
4367     entries[0].fRecursive = TRUE;
4368
4369     notifyID = SHChangeNotifyRegister(wnd, SHCNRF_ShellLevel,
4370             SHCNE_ALLEVENTS, WM_USER_NOTIFY, 1, entries);
4371     ok(notifyID != 0, "Failed to register a window for change notifications\n");
4372
4373     for(i = 0; i < sizeof(chnotify_tests) / sizeof(*chnotify_tests); ++i){
4374         exp_data = chnotify_tests + i;
4375
4376         exp_data->missing_events = exp_data->notify_count;
4377         SHChangeNotify(exp_data->signal, SHCNF_PATHA | SHCNF_FLUSH,
4378                 strlen(exp_data->path_1) > 0 ? exp_data->path_1 : NULL,
4379                 strlen(exp_data->path_2) > 0 ? exp_data->path_2 : NULL);
4380         do_events();
4381         ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
4382
4383         if(has_unicode){
4384             WCHAR *path1, *path2;
4385
4386             path1 = make_wstr(exp_data->path_1);
4387             path2 = make_wstr(exp_data->path_2);
4388
4389             exp_data->missing_events = exp_data->notify_count;
4390             SHChangeNotify(exp_data->signal, SHCNF_PATHW | SHCNF_FLUSH, path1, path2);
4391             do_events();
4392             ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
4393         }
4394     }
4395
4396     SHChangeNotifyDeregister(notifyID);
4397     DestroyWindow(wnd);
4398
4399     br = RemoveDirectoryA(root_dirA);
4400     ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4401 }
4402
4403 START_TEST(shlfolder)
4404 {
4405     init_function_pointers();
4406     /* if OleInitialize doesn't get called, ParseDisplayName returns
4407        CO_E_NOTINITIALIZED for malformed directory names on win2k. */
4408     OleInitialize(NULL);
4409
4410     test_ParseDisplayName();
4411     test_SHParseDisplayName();
4412     test_BindToObject();
4413     test_EnumObjects_and_CompareIDs();
4414     test_GetDisplayName();
4415     test_GetAttributesOf();
4416     test_SHGetPathFromIDList();
4417     test_CallForAttributes();
4418     test_FolderShortcut();
4419     test_ITEMIDLIST_format();
4420     test_SHGetFolderPathA();
4421     test_SHGetFolderPathAndSubDirA();
4422     test_LocalizedNames();
4423     test_SHCreateShellItem();
4424     test_SHCreateShellItemArray();
4425     test_desktop_IPersist();
4426     test_GetUIObject();
4427     test_SHSimpleIDListFromPath();
4428     test_ParseDisplayNamePBC();
4429     test_SHGetNameFromIDList();
4430     test_SHGetItemFromDataObject();
4431     test_SHGetIDListFromObject();
4432     test_SHGetItemFromObject();
4433     test_ShellItemCompare();
4434     test_SHChangeNotify();
4435     test_ShellItemBindToHandler();
4436
4437     OleUninitialize();
4438 }