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