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