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