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