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