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