shell32/tests: Move a test_argify() check so it is run even if we could not create...
[wine.git] / dlls / shell32 / tests / shlfolder.c
blobda903b0445d14fc3038ea50372cd61f28609666b
1 /*
2 * Unit test of the IShellFolder functions.
4 * Copyright 2004 Vitaliy Margolen
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.
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.
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
21 #include <stdarg.h>
22 #include <stdio.h>
24 #define COBJMACROS
25 #define CONST_VTABLE
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wtypes.h"
30 #include "shellapi.h"
33 #include "shlguid.h"
34 #include "shlobj.h"
35 #include "shobjidl.h"
36 #include "shlwapi.h"
37 #include "ocidl.h"
38 #include "oleauto.h"
40 #include "wine/test.h"
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);
46 static IMalloc *ppM;
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 *pSHCreateShellItemArrayFromIDLists)(UINT, PCIDLIST_ABSOLUTE*, IShellItemArray**);
64 static HRESULT (WINAPI *pSHCreateShellItemArrayFromDataObject)(IDataObject*, REFIID, void **);
65 static HRESULT (WINAPI *pSHCreateShellItemArrayFromShellItem)(IShellItem*, REFIID, void **);
66 static LPITEMIDLIST (WINAPI *pILCombine)(LPCITEMIDLIST,LPCITEMIDLIST);
67 static HRESULT (WINAPI *pSHParseDisplayName)(LPCWSTR,IBindCtx*,LPITEMIDLIST*,SFGAOF,SFGAOF*);
68 static LPITEMIDLIST (WINAPI *pSHSimpleIDListFromPathAW)(LPCVOID);
69 static HRESULT (WINAPI *pSHGetNameFromIDList)(PCIDLIST_ABSOLUTE,SIGDN,PWSTR*);
70 static HRESULT (WINAPI *pSHGetItemFromDataObject)(IDataObject*,DATAOBJ_GET_ITEM_FLAGS,REFIID,void**);
71 static HRESULT (WINAPI *pSHGetIDListFromObject)(IUnknown*, PIDLIST_ABSOLUTE*);
72 static HRESULT (WINAPI *pSHGetItemFromObject)(IUnknown*,REFIID,void**);
73 static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
74 static UINT (WINAPI *pGetSystemWow64DirectoryW)(LPWSTR, UINT);
75 static HRESULT (WINAPI *pSHCreateDefaultContextMenu)(const DEFCONTEXTMENU*,REFIID,void**);
76 static HRESULT (WINAPI *pSHCreateShellFolderView)(const SFV_CREATE *pcsfv, IShellView **ppsv);
77 static HRESULT (WINAPI *pSHCreateShellFolderViewEx)(LPCSFV psvcbi, IShellView **ppv);
78 static HRESULT (WINAPI *pSHILCreateFromPath)(LPCWSTR, LPITEMIDLIST *,DWORD*);
80 static WCHAR *make_wstr(const char *str)
82 WCHAR *ret;
83 int len;
85 if (!str || !str[0])
86 return NULL;
88 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
89 if(!len || len < 0)
90 return NULL;
92 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
93 if(!ret)
94 return NULL;
96 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
97 return ret;
100 static int strcmp_wa(LPCWSTR strw, const char *stra)
102 CHAR buf[512];
103 WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL);
104 return lstrcmpA(stra, buf);
107 static void init_function_pointers(void)
109 HMODULE hmod;
110 HRESULT hr;
111 void *ptr;
113 hmod = GetModuleHandleA("shell32.dll");
115 #define MAKEFUNC(f) (p##f = (void*)GetProcAddress(hmod, #f))
116 MAKEFUNC(SHBindToParent);
117 MAKEFUNC(SHCreateItemFromIDList);
118 MAKEFUNC(SHCreateItemFromParsingName);
119 MAKEFUNC(SHCreateShellItem);
120 MAKEFUNC(SHCreateShellItemArray);
121 MAKEFUNC(SHCreateShellItemArrayFromIDLists);
122 MAKEFUNC(SHCreateShellItemArrayFromDataObject);
123 MAKEFUNC(SHCreateShellItemArrayFromShellItem);
124 MAKEFUNC(SHGetFolderPathA);
125 MAKEFUNC(SHGetFolderPathAndSubDirA);
126 MAKEFUNC(SHGetPathFromIDListW);
127 MAKEFUNC(SHGetSpecialFolderPathA);
128 MAKEFUNC(SHGetSpecialFolderPathW);
129 MAKEFUNC(SHGetSpecialFolderLocation);
130 MAKEFUNC(SHParseDisplayName);
131 MAKEFUNC(SHGetNameFromIDList);
132 MAKEFUNC(SHGetItemFromDataObject);
133 MAKEFUNC(SHGetIDListFromObject);
134 MAKEFUNC(SHGetItemFromObject);
135 MAKEFUNC(SHCreateDefaultContextMenu);
136 MAKEFUNC(SHCreateShellFolderView);
137 MAKEFUNC(SHCreateShellFolderViewEx);
138 #undef MAKEFUNC
140 #define MAKEFUNC_ORD(f, ord) (p##f = (void*)GetProcAddress(hmod, (LPSTR)(ord)))
141 MAKEFUNC_ORD(ILFindLastID, 16);
142 MAKEFUNC_ORD(ILIsEqual, 21);
143 MAKEFUNC_ORD(ILCombine, 25);
144 MAKEFUNC_ORD(SHILCreateFromPath, 28);
145 MAKEFUNC_ORD(ILFree, 155);
146 MAKEFUNC_ORD(SHSimpleIDListFromPathAW, 162);
147 #undef MAKEFUNC_ORD
149 /* test named exports */
150 ptr = GetProcAddress(hmod, "ILFree");
151 ok(broken(ptr == 0) || ptr != 0, "expected named export for ILFree\n");
152 if (ptr)
154 #define TESTNAMED(f) \
155 ptr = (void*)GetProcAddress(hmod, #f); \
156 ok(ptr != 0, "expected named export for " #f "\n");
158 TESTNAMED(ILAppendID);
159 TESTNAMED(ILClone);
160 TESTNAMED(ILCloneFirst);
161 TESTNAMED(ILCombine);
162 TESTNAMED(ILCreateFromPath);
163 TESTNAMED(ILCreateFromPathA);
164 TESTNAMED(ILCreateFromPathW);
165 TESTNAMED(ILFindChild);
166 TESTNAMED(ILFindLastID);
167 TESTNAMED(ILGetNext);
168 TESTNAMED(ILGetSize);
169 TESTNAMED(ILIsEqual);
170 TESTNAMED(ILIsParent);
171 TESTNAMED(ILRemoveLastID);
172 TESTNAMED(ILSaveToStream);
173 #undef TESTNAMED
176 hmod = GetModuleHandleA("shlwapi.dll");
177 pStrRetToBufW = (void*)GetProcAddress(hmod, "StrRetToBufW");
179 hmod = GetModuleHandleA("kernel32.dll");
180 pIsWow64Process = (void*)GetProcAddress(hmod, "IsWow64Process");
181 pGetSystemWow64DirectoryW = (void*)GetProcAddress(hmod, "GetSystemWow64DirectoryW");
183 hr = SHGetMalloc(&ppM);
184 ok(hr == S_OK, "SHGetMalloc failed %08x\n", hr);
187 /* Based on PathAddBackslashW from dlls/shlwapi/path.c */
188 static LPWSTR myPathAddBackslashW( LPWSTR lpszPath )
190 size_t iLen;
192 if (!lpszPath || (iLen = lstrlenW(lpszPath)) >= MAX_PATH)
193 return NULL;
195 if (iLen)
197 lpszPath += iLen;
198 if (lpszPath[-1] != '\\')
200 *lpszPath++ = '\\';
201 *lpszPath = '\0';
204 return lpszPath;
207 static void test_ParseDisplayName(void)
209 HRESULT hr;
210 IShellFolder *IDesktopFolder;
211 static const char *cNonExistDir1A = "c:\\nonexist_subdir";
212 static const char *cNonExistDir2A = "c:\\\\nonexist_subdir";
213 static const char *cInetTestA = "http:\\yyy";
214 static const char *cInetTest2A = "xx:yyy";
215 DWORD res;
216 WCHAR cTestDirW [MAX_PATH] = {0};
217 ITEMIDLIST *newPIDL;
218 BOOL bRes;
220 hr = SHGetDesktopFolder(&IDesktopFolder);
221 ok(hr == S_OK, "Expected SHGetDesktopFolder to return S_OK, got 0x%08x\n", hr);
222 if(hr != S_OK) return;
224 /* Tests crash on W2K and below (SHCreateShellItem available as of XP) */
225 if (pSHCreateShellItem)
227 if (0)
229 /* null name and pidl, also crashes on Windows 8 */
230 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL,
231 NULL, NULL, NULL, 0);
232 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
235 /* null name */
236 newPIDL = (ITEMIDLIST*)0xdeadbeef;
237 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
238 NULL, NULL, NULL, NULL, &newPIDL, 0);
239 ok(newPIDL == 0, "expected null, got %p\n", newPIDL);
240 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
242 else
243 win_skip("Tests would crash on W2K and below\n");
245 MultiByteToWideChar(CP_ACP, 0, cInetTestA, -1, cTestDirW, MAX_PATH);
246 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
247 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
248 todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
249 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
250 if (hr == S_OK)
252 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
253 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
254 IMalloc_Free(ppM, newPIDL);
257 MultiByteToWideChar(CP_ACP, 0, cInetTest2A, -1, cTestDirW, MAX_PATH);
258 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
259 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
260 todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
261 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
262 if (hr == S_OK)
264 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
265 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
266 IMalloc_Free(ppM, newPIDL);
269 res = GetFileAttributesA(cNonExistDir1A);
270 if(res != INVALID_FILE_ATTRIBUTES)
272 skip("Test directory unexpectedly exists\n");
273 goto finished;
276 MultiByteToWideChar(CP_ACP, 0, cNonExistDir1A, -1, cTestDirW, MAX_PATH);
277 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
278 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
279 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL),
280 "ParseDisplayName returned %08x, expected 80070002 or E_FAIL\n", hr);
282 res = GetFileAttributesA(cNonExistDir2A);
283 if(res != INVALID_FILE_ATTRIBUTES)
285 skip("Test directory unexpectedly exists\n");
286 goto finished;
289 MultiByteToWideChar(CP_ACP, 0, cNonExistDir2A, -1, cTestDirW, MAX_PATH);
290 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
291 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
292 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL) || (hr == E_INVALIDARG),
293 "ParseDisplayName returned %08x, expected 80070002, E_FAIL or E_INVALIDARG\n", hr);
295 /* I thought that perhaps the DesktopFolder's ParseDisplayName would recognize the
296 * path corresponding to CSIDL_PERSONAL and return a CLSID_MyDocuments PIDL. Turns
297 * out it doesn't. The magic seems to happen in the file dialogs, then. */
298 if (!pSHGetSpecialFolderPathW || !pILFindLastID)
300 win_skip("SHGetSpecialFolderPathW and/or ILFindLastID are not available\n");
301 goto finished;
304 bRes = pSHGetSpecialFolderPathW(NULL, cTestDirW, CSIDL_PERSONAL, FALSE);
305 ok(bRes, "SHGetSpecialFolderPath(CSIDL_PERSONAL) failed! %u\n", GetLastError());
306 if (!bRes) goto finished;
308 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
309 ok(hr == S_OK, "DesktopFolder->ParseDisplayName failed. hr = %08x.\n", hr);
310 if (hr != S_OK) goto finished;
312 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x31 ||
313 pILFindLastID(newPIDL)->mkid.abID[0] == 0xb1, /* Win98 */
314 "Last pidl should be of type PT_FOLDER or PT_IESPECIAL2, but is: %02x\n",
315 pILFindLastID(newPIDL)->mkid.abID[0]);
316 IMalloc_Free(ppM, newPIDL);
318 finished:
319 IShellFolder_Release(IDesktopFolder);
322 /* creates a file with the specified name for tests */
323 static void CreateTestFile(const CHAR *name)
325 HANDLE file;
326 DWORD written;
328 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
329 if (file != INVALID_HANDLE_VALUE)
331 WriteFile(file, name, strlen(name), &written, NULL);
332 WriteFile(file, "\n", strlen("\n"), &written, NULL);
333 CloseHandle(file);
338 /* initializes the tests */
339 static void CreateFilesFolders(void)
341 CreateDirectoryA(".\\testdir", NULL);
342 CreateDirectoryA(".\\testdir\\test.txt", NULL);
343 CreateTestFile (".\\testdir\\test1.txt ");
344 CreateTestFile (".\\testdir\\test2.txt ");
345 CreateTestFile (".\\testdir\\test3.txt ");
346 CreateDirectoryA(".\\testdir\\testdir2 ", NULL);
347 CreateDirectoryA(".\\testdir\\testdir2\\subdir", NULL);
350 /* cleans after tests */
351 static void Cleanup(void)
353 DeleteFileA(".\\testdir\\test1.txt");
354 DeleteFileA(".\\testdir\\test2.txt");
355 DeleteFileA(".\\testdir\\test3.txt");
356 RemoveDirectoryA(".\\testdir\\test.txt");
357 RemoveDirectoryA(".\\testdir\\testdir2\\subdir");
358 RemoveDirectoryA(".\\testdir\\testdir2");
359 RemoveDirectoryA(".\\testdir");
363 /* perform test */
364 static void test_EnumObjects(IShellFolder *iFolder)
366 IEnumIDList *iEnumList;
367 LPITEMIDLIST newPIDL, idlArr[10];
368 ULONG NumPIDLs;
369 int i=0, j;
370 HRESULT hr;
372 static const WORD iResults [5][5] =
374 { 0,-1,-1,-1,-1},
375 { 1, 0,-1,-1,-1},
376 { 1, 1, 0,-1,-1},
377 { 1, 1, 1, 0,-1},
378 { 1, 1, 1, 1, 0}
381 #define SFGAO_testfor SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | SFGAO_CAPABILITYMASK
382 /* Don't test for SFGAO_HASSUBFOLDER since we return real state and native cached */
383 static const ULONG attrs[5] =
385 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
386 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
387 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
388 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
389 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
391 static const ULONG full_attrs[5] =
393 SFGAO_CAPABILITYMASK | SFGAO_STORAGE | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
394 SFGAO_CAPABILITYMASK | SFGAO_STORAGE | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
395 SFGAO_CAPABILITYMASK | SFGAO_STREAM | SFGAO_FILESYSTEM,
396 SFGAO_CAPABILITYMASK | SFGAO_STREAM | SFGAO_FILESYSTEM,
397 SFGAO_CAPABILITYMASK | SFGAO_STREAM | SFGAO_FILESYSTEM,
400 hr = IShellFolder_EnumObjects(iFolder, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &iEnumList);
401 ok(hr == S_OK, "EnumObjects failed %08x\n", hr);
403 /* This is to show that, contrary to what is said on MSDN, on IEnumIDList::Next,
404 * the filesystem shellfolders return S_OK even if less than 'celt' items are
405 * returned (in contrast to S_FALSE). We have to do it in a loop since WinXP
406 * only ever returns a single entry per call. */
407 while (IEnumIDList_Next(iEnumList, 10-i, &idlArr[i], &NumPIDLs) == S_OK)
408 i += NumPIDLs;
409 ok (i == 5, "i: %d\n", i);
411 hr = IEnumIDList_Release(iEnumList);
412 ok(hr == S_OK, "IEnumIDList_Release failed %08x\n", hr);
414 /* Sort them first in case of wrong order from system */
415 for (i=0;i<5;i++) for (j=0;j<5;j++)
416 if ((SHORT)IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]) < 0)
418 newPIDL = idlArr[i];
419 idlArr[i] = idlArr[j];
420 idlArr[j] = newPIDL;
423 for (i=0;i<5;i++) for (j=0;j<5;j++)
425 hr = IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]);
426 ok(hr == iResults[i][j], "Got %x expected [%d]-[%d]=%x\n", hr, i, j, iResults[i][j]);
430 for (i = 0; i < 5; i++)
432 SFGAOF flags;
433 #define SFGAO_VISTA SFGAO_DROPTARGET | SFGAO_CANLINK | SFGAO_CANCOPY
434 /* Native returns all flags no matter what we ask for */
435 flags = SFGAO_CANCOPY;
436 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
437 flags &= SFGAO_testfor;
438 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
439 ok(flags == (attrs[i]) ||
440 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR) || /* Win9x, NT4 */
441 flags == ((attrs[i] & ~SFGAO_CAPABILITYMASK) | SFGAO_VISTA), /* Vista and higher */
442 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
444 flags = SFGAO_testfor;
445 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
446 flags &= SFGAO_testfor;
447 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
448 ok(flags == attrs[i] ||
449 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR), /* Win9x, NT4 */
450 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
452 flags = ~0u;
453 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
454 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
455 ok((flags & ~SFGAO_HASSUBFOLDER) == full_attrs[i], "%d: got %08x expected %08x\n", i, flags, full_attrs[i]);
458 for (i=0;i<5;i++)
459 IMalloc_Free(ppM, idlArr[i]);
462 static void test_BindToObject(void)
464 HRESULT hr;
465 UINT cChars;
466 IShellFolder *psfDesktop, *psfChild, *psfMyComputer, *psfSystemDir;
467 SHITEMID emptyitem = { 0, { 0 } };
468 LPITEMIDLIST pidlMyComputer, pidlSystemDir, pidl, pidlEmpty = (LPITEMIDLIST)&emptyitem;
469 WCHAR wszSystemDir[MAX_PATH];
470 char szSystemDir[MAX_PATH];
471 char buf[MAX_PATH];
472 WCHAR path[MAX_PATH];
473 CHAR pathA[MAX_PATH];
474 HANDLE hfile;
475 WCHAR wszMyComputer[] = {
476 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
477 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
478 static const CHAR filename_html[] = "winetest.html";
479 static const CHAR filename_txt[] = "winetest.txt";
480 static const CHAR filename_foo[] = "winetest.foo";
482 /* The following tests shows that BindToObject should fail with E_INVALIDARG if called
483 * with an empty pidl. This is tested for Desktop, MyComputer and the FS ShellFolder
485 hr = SHGetDesktopFolder(&psfDesktop);
486 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
487 if (hr != S_OK) return;
489 hr = IShellFolder_BindToObject(psfDesktop, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
490 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
492 hr = IShellFolder_BindToObject(psfDesktop, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
493 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
495 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
496 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
497 if (hr != S_OK) {
498 IShellFolder_Release(psfDesktop);
499 return;
502 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
503 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
504 IShellFolder_Release(psfDesktop);
505 IMalloc_Free(ppM, pidlMyComputer);
506 if (hr != S_OK) return;
508 hr = IShellFolder_BindToObject(psfMyComputer, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
509 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
511 if (0)
513 /* this call segfaults on 98SE */
514 hr = IShellFolder_BindToObject(psfMyComputer, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
515 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
518 cChars = GetSystemDirectoryA(szSystemDir, MAX_PATH);
519 ok (cChars > 0 && cChars < MAX_PATH, "GetSystemDirectoryA failed! LastError: %u\n", GetLastError());
520 if (cChars == 0 || cChars >= MAX_PATH) {
521 IShellFolder_Release(psfMyComputer);
522 return;
524 MultiByteToWideChar(CP_ACP, 0, szSystemDir, -1, wszSystemDir, MAX_PATH);
526 hr = IShellFolder_ParseDisplayName(psfMyComputer, NULL, NULL, wszSystemDir, NULL, &pidlSystemDir, NULL);
527 ok (hr == S_OK, "MyComputers's ParseDisplayName failed to parse the SystemDirectory! hr = %08x\n", hr);
528 if (hr != S_OK) {
529 IShellFolder_Release(psfMyComputer);
530 return;
533 hr = IShellFolder_BindToObject(psfMyComputer, pidlSystemDir, NULL, &IID_IShellFolder, (LPVOID*)&psfSystemDir);
534 ok (hr == S_OK, "MyComputer failed to bind to a FileSystem ShellFolder! hr = %08x\n", hr);
535 IShellFolder_Release(psfMyComputer);
536 IMalloc_Free(ppM, pidlSystemDir);
537 if (hr != S_OK) return;
539 hr = IShellFolder_BindToObject(psfSystemDir, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
540 ok (hr == E_INVALIDARG,
541 "FileSystem ShellFolder's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
543 if (0)
545 /* this call segfaults on 98SE */
546 hr = IShellFolder_BindToObject(psfSystemDir, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
547 ok (hr == E_INVALIDARG,
548 "FileSystem ShellFolder's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
551 IShellFolder_Release(psfSystemDir);
553 cChars = GetCurrentDirectoryA(MAX_PATH, buf);
554 if(!cChars)
556 skip("Failed to get current directory, skipping tests.\n");
557 return;
559 if(buf[cChars-1] != '\\') lstrcatA(buf, "\\");
561 SHGetDesktopFolder(&psfDesktop);
563 /* Attempt BindToObject on files. */
565 /* .html */
566 lstrcpyA(pathA, buf);
567 lstrcatA(pathA, filename_html);
568 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
569 if(hfile != INVALID_HANDLE_VALUE)
571 CloseHandle(hfile);
572 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
573 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
574 ok(hr == S_OK, "Got 0x%08x\n", hr);
575 if(SUCCEEDED(hr))
577 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
578 ok(hr == S_OK ||
579 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
580 "Got 0x%08x\n", hr);
581 if(SUCCEEDED(hr))
583 IPersist *pp;
584 hr = IShellFolder_QueryInterface(psfChild, &IID_IPersist, (void**)&pp);
585 ok(hr == S_OK ||
586 broken(hr == E_NOINTERFACE), /* Win9x, NT4, W2K */
587 "Got 0x%08x\n", hr);
588 if(SUCCEEDED(hr))
590 CLSID id;
591 hr = IPersist_GetClassID(pp, &id);
592 ok(hr == S_OK, "Got 0x%08x\n", hr);
593 /* CLSID_ShellFSFolder on some w2k systems */
594 ok(IsEqualIID(&id, &CLSID_ShellDocObjView) || broken(IsEqualIID(&id, &CLSID_ShellFSFolder)),
595 "Unexpected classid %s\n", wine_dbgstr_guid(&id));
596 IPersist_Release(pp);
599 IShellFolder_Release(psfChild);
601 pILFree(pidl);
603 DeleteFileA(pathA);
605 else
606 win_skip("Failed to create .html testfile.\n");
608 /* .txt */
609 lstrcpyA(pathA, buf);
610 lstrcatA(pathA, filename_txt);
611 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
612 if(hfile != INVALID_HANDLE_VALUE)
614 CloseHandle(hfile);
615 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
616 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
617 ok(hr == S_OK, "Got 0x%08x\n", hr);
618 if(SUCCEEDED(hr))
620 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
621 ok(hr == E_FAIL || /* Vista+ */
622 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || /* XP, W2K3 */
623 hr == E_INVALIDARG || /* W2K item in top dir */
624 broken(hr == S_OK), /* Win9x, NT4, W2K */
625 "Got 0x%08x\n", hr);
626 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
627 pILFree(pidl);
629 DeleteFileA(pathA);
631 else
632 win_skip("Failed to create .txt testfile.\n");
634 /* .foo */
635 lstrcpyA(pathA, buf);
636 lstrcatA(pathA, filename_foo);
637 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
638 if(hfile != INVALID_HANDLE_VALUE)
640 CloseHandle(hfile);
641 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
642 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
643 ok(hr == S_OK, "Got 0x%08x\n", hr);
644 if(SUCCEEDED(hr))
646 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
647 ok(hr == E_FAIL || /* Vista+ */
648 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || /* XP, W2K3 */
649 hr == E_INVALIDARG || /* W2K item in top dir */
650 broken(hr == S_OK), /* Win9x, NT4, W2K */
651 "Got 0x%08x\n", hr);
652 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
653 pILFree(pidl);
655 DeleteFileA(pathA);
657 else
658 win_skip("Failed to create .foo testfile.\n");
660 /* And on the desktop */
661 if(pSHGetSpecialFolderPathA)
663 pSHGetSpecialFolderPathA(NULL, pathA, CSIDL_DESKTOP, FALSE);
664 lstrcatA(pathA, "\\");
665 lstrcatA(pathA, filename_html);
666 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
667 if(hfile != INVALID_HANDLE_VALUE)
669 CloseHandle(hfile);
670 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
671 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
672 ok(hr == S_OK, "Got 0x%08x\n", hr);
673 if(SUCCEEDED(hr))
675 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
676 ok(hr == S_OK ||
677 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
678 "Got 0x%08x\n", hr);
679 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
680 pILFree(pidl);
682 if(!DeleteFileA(pathA))
683 trace("Failed to delete: %d\n", GetLastError());
686 else
687 win_skip("Failed to create .html testfile.\n");
689 pSHGetSpecialFolderPathA(NULL, pathA, CSIDL_DESKTOP, FALSE);
690 lstrcatA(pathA, "\\");
691 lstrcatA(pathA, filename_foo);
692 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
693 if(hfile != INVALID_HANDLE_VALUE)
695 CloseHandle(hfile);
696 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
697 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
698 ok(hr == S_OK, "Got 0x%08x\n", hr);
699 if(SUCCEEDED(hr))
701 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
702 ok(hr == E_FAIL || /* Vista+ */
703 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || /* XP, W2K3 */
704 broken(hr == S_OK), /* Win9x, NT4, W2K */
705 "Got 0x%08x\n", hr);
706 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
707 pILFree(pidl);
709 DeleteFileA(pathA);
711 else
712 win_skip("Failed to create .foo testfile.\n");
715 IShellFolder_Release(psfDesktop);
718 static void test_GetDisplayName(void)
720 BOOL result;
721 HRESULT hr;
722 HANDLE hTestFile;
723 WCHAR wszTestFile[MAX_PATH], wszTestFile2[MAX_PATH];
724 char szTestFile[MAX_PATH], szTestDir[MAX_PATH];
725 DWORD attr;
726 STRRET strret;
727 LPSHELLFOLDER psfDesktop, psfPersonal;
728 IUnknown *psfFile;
729 SHITEMID emptyitem = { 0, { 0 } };
730 LPITEMIDLIST pidlTestFile, pidlEmpty = (LPITEMIDLIST)&emptyitem;
731 LPCITEMIDLIST pidlLast;
732 static const CHAR szFileName[] = "winetest.foo";
733 static const WCHAR wszFileName[] = { 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
734 static const WCHAR wszDirName[] = { 'w','i','n','e','t','e','s','t',0 };
736 /* I'm trying to figure if there is a functional difference between calling
737 * SHGetPathFromIDListW and calling GetDisplayNameOf(SHGDN_FORPARSING) after
738 * binding to the shellfolder. One thing I thought of was that perhaps
739 * SHGetPathFromIDListW would be able to get the path to a file, which does
740 * not exist anymore, while the other method wouldn't. It turns out there's
741 * no functional difference in this respect.
744 if(!pSHGetSpecialFolderPathA) {
745 win_skip("SHGetSpecialFolderPathA is not available\n");
746 return;
749 /* First creating a directory in MyDocuments and a file in this directory. */
750 result = pSHGetSpecialFolderPathA(NULL, szTestDir, CSIDL_PERSONAL, FALSE);
751 ok(result, "SHGetSpecialFolderPathA failed! Last error: %u\n", GetLastError());
752 if (!result) return;
754 /* Use ANSI file functions so this works on Windows 9x */
755 lstrcatA(szTestDir, "\\winetest");
756 CreateDirectoryA(szTestDir, NULL);
757 attr=GetFileAttributesA(szTestDir);
758 if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY))
760 ok(0, "unable to create the '%s' directory\n", szTestDir);
761 return;
764 lstrcpyA(szTestFile, szTestDir);
765 lstrcatA(szTestFile, "\\");
766 lstrcatA(szTestFile, szFileName);
767 hTestFile = CreateFileA(szTestFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
768 ok((hTestFile != INVALID_HANDLE_VALUE), "CreateFileA failed! Last error: %u\n", GetLastError());
769 if (hTestFile == INVALID_HANDLE_VALUE) return;
770 CloseHandle(hTestFile);
772 /* Getting an itemidlist for the file. */
773 hr = SHGetDesktopFolder(&psfDesktop);
774 ok(hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
775 if (hr != S_OK) return;
777 MultiByteToWideChar(CP_ACP, 0, szTestFile, -1, wszTestFile, MAX_PATH);
779 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
780 ok(hr == S_OK, "Desktop->ParseDisplayName failed! hr = %08x\n", hr);
781 if (hr != S_OK) {
782 IShellFolder_Release(psfDesktop);
783 return;
786 pidlLast = pILFindLastID(pidlTestFile);
787 ok(pidlLast->mkid.cb >=76 ||
788 broken(pidlLast->mkid.cb == 28) || /* W2K */
789 broken(pidlLast->mkid.cb == 40), /* Win9x, WinME */
790 "Expected pidl length of at least 76, got %d.\n", pidlLast->mkid.cb);
791 if (pidlLast->mkid.cb >= 28) {
792 ok(!lstrcmpA((CHAR*)&pidlLast->mkid.abID[12], szFileName),
793 "Filename should be stored as ansi-string at this position!\n");
795 /* WinXP and up store the filenames as both ANSI and UNICODE in the pidls */
796 if (pidlLast->mkid.cb >= 76) {
797 ok(!lstrcmpW((WCHAR*)&pidlLast->mkid.abID[46], wszFileName) ||
798 (pidlLast->mkid.cb >= 94 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[64], wszFileName)) || /* Vista */
799 (pidlLast->mkid.cb >= 98 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[68], wszFileName)) || /* Win7 */
800 (pidlLast->mkid.cb >= 102 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[72], wszFileName)), /* Win8 */
801 "Filename should be stored as wchar-string at this position!\n");
804 /* It seems as if we cannot bind to regular files on windows, but only directories.
806 hr = IShellFolder_BindToObject(psfDesktop, pidlTestFile, NULL, &IID_IUnknown, (VOID**)&psfFile);
807 ok (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
808 hr == E_NOTIMPL || /* Vista */
809 broken(hr == S_OK), /* Win9x, W2K */
810 "hr = %08x\n", hr);
811 if (hr == S_OK) {
812 IUnknown_Release(psfFile);
815 if (!pSHBindToParent)
817 win_skip("SHBindToParent is missing\n");
818 DeleteFileA(szTestFile);
819 RemoveDirectoryA(szTestDir);
820 return;
823 /* Some tests for IShellFolder::SetNameOf */
824 if (pSHGetFolderPathAndSubDirA)
826 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
827 ok(hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
828 if (hr == S_OK) {
829 /* It's ok to use this fixed path. Call will fail anyway. */
830 WCHAR wszAbsoluteFilename[] = { 'C',':','\\','w','i','n','e','t','e','s','t', 0 };
831 LPITEMIDLIST pidlNew;
833 /* The pidl returned through the last parameter of SetNameOf is a simple one. */
834 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlLast, wszDirName, SHGDN_NORMAL, &pidlNew);
835 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
836 if (hr == S_OK)
838 ok (((LPITEMIDLIST)((LPBYTE)pidlNew+pidlNew->mkid.cb))->mkid.cb == 0,
839 "pidl returned from SetNameOf should be simple!\n");
841 /* Passing an absolute path to SetNameOf fails. The HRESULT code indicates that SetNameOf
842 * is implemented on top of SHFileOperation in WinXP. */
843 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszAbsoluteFilename,
844 SHGDN_FORPARSING, NULL);
845 ok (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED), "SetNameOf succeeded! hr = %08x\n", hr);
847 /* Rename the file back to its original name. SetNameOf ignores the fact, that the
848 * SHGDN flags specify an absolute path. */
849 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszFileName, SHGDN_FORPARSING, NULL);
850 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
852 pILFree(pidlNew);
855 IShellFolder_Release(psfPersonal);
858 else
859 win_skip("Avoid needs of interaction on Win2k\n");
861 /* Deleting the file and the directory */
862 DeleteFileA(szTestFile);
863 RemoveDirectoryA(szTestDir);
865 /* SHGetPathFromIDListW still works, although the file is not present anymore. */
866 if (pSHGetPathFromIDListW)
868 result = pSHGetPathFromIDListW(pidlTestFile, wszTestFile2);
869 ok (result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
870 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "SHGetPathFromIDListW returns incorrect path!\n");
873 /* SHBindToParent fails, if called with a NULL PIDL. */
874 hr = pSHBindToParent(NULL, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
875 ok (hr != S_OK, "SHBindToParent(NULL) should fail!\n");
877 /* But it succeeds with an empty PIDL. */
878 hr = pSHBindToParent(pidlEmpty, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
879 ok (hr == S_OK, "SHBindToParent(empty PIDL) should succeed! hr = %08x\n", hr);
880 ok (pidlLast == pidlEmpty, "The last element of an empty PIDL should be the PIDL itself!\n");
881 if (hr == S_OK)
882 IShellFolder_Release(psfPersonal);
884 /* Binding to the folder and querying the display name of the file also works. */
885 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
886 ok (hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
887 if (hr != S_OK) {
888 IShellFolder_Release(psfDesktop);
889 return;
892 /* This test shows that Windows doesn't allocate a new pidlLast, but returns a pointer into
893 * pidlTestFile (In accordance with MSDN). */
894 ok (pILFindLastID(pidlTestFile) == pidlLast,
895 "SHBindToParent doesn't return the last id of the pidl param!\n");
897 hr = IShellFolder_GetDisplayNameOf(psfPersonal, pidlLast, SHGDN_FORPARSING, &strret);
898 ok (hr == S_OK, "Personal->GetDisplayNameOf failed! hr = %08x\n", hr);
899 if (hr != S_OK) {
900 IShellFolder_Release(psfDesktop);
901 IShellFolder_Release(psfPersonal);
902 return;
905 if (pStrRetToBufW)
907 hr = pStrRetToBufW(&strret, pidlLast, wszTestFile2, MAX_PATH);
908 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
909 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "GetDisplayNameOf returns incorrect path!\n");
912 ILFree(pidlTestFile);
913 IShellFolder_Release(psfDesktop);
914 IShellFolder_Release(psfPersonal);
917 static void test_CallForAttributes(void)
919 HKEY hKey;
920 LONG lResult;
921 HRESULT hr;
922 DWORD dwSize;
923 LPSHELLFOLDER psfDesktop;
924 LPITEMIDLIST pidlMyDocuments;
925 DWORD dwAttributes, dwCallForAttributes, dwOrigAttributes, dwOrigCallForAttributes;
926 static const WCHAR wszAttributes[] = { 'A','t','t','r','i','b','u','t','e','s',0 };
927 static const WCHAR wszCallForAttributes[] = {
928 'C','a','l','l','F','o','r','A','t','t','r','i','b','u','t','e','s',0 };
929 static const WCHAR wszMyDocumentsKey[] = {
930 'C','L','S','I','D','\\','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-',
931 '1','1','D','0','-','9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',
932 '\\','S','h','e','l','l','F','o','l','d','e','r',0 };
933 WCHAR wszMyDocuments[] = {
934 ':',':','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-','1','1','D','0','-',
935 '9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',0 };
937 /* For the root of a namespace extension, the attributes are not queried by binding
938 * to the object and calling GetAttributesOf. Instead, the attributes are read from
939 * the registry value HKCR/CLSID/{...}/ShellFolder/Attributes. This is documented on MSDN.
941 * The MyDocuments shellfolder on WinXP has a HKCR/CLSID/{...}/ShellFolder/CallForAttributes
942 * value. It seems that if the folder is queried for one of the flags set in CallForAttributes,
943 * the shell does bind to the folder object and calls GetAttributesOf. This is not documented
944 * on MSDN. This test is meant to document the observed behaviour on WinXP SP2.
946 hr = SHGetDesktopFolder(&psfDesktop);
947 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
948 if (hr != S_OK) return;
950 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyDocuments, NULL,
951 &pidlMyDocuments, NULL);
952 ok (hr == S_OK ||
953 broken(hr == E_INVALIDARG), /* Win95, NT4 */
954 "Desktop's ParseDisplayName failed to parse MyDocuments's CLSID! hr = %08x\n", hr);
955 if (hr != S_OK) {
956 IShellFolder_Release(psfDesktop);
957 return;
960 dwAttributes = 0xffffffff;
961 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
962 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
963 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
965 /* We need the following setup (as observed on WinXP SP2), for the tests to make sense. */
966 ok (dwAttributes & SFGAO_FILESYSTEM, "SFGAO_FILESYSTEM attribute is not set for MyDocuments!\n");
967 ok (!(dwAttributes & SFGAO_ISSLOW), "SFGAO_ISSLOW attribute is set for MyDocuments!\n");
968 ok (!(dwAttributes & SFGAO_GHOSTED), "SFGAO_GHOSTED attribute is set for MyDocuments!\n");
970 /* We don't have the MyDocuments shellfolder in wine yet, and thus we don't have the registry
971 * key. So the test will return at this point, if run on wine.
973 lResult = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszMyDocumentsKey, 0, KEY_WRITE|KEY_READ, &hKey);
974 ok (lResult == ERROR_SUCCESS ||
975 lResult == ERROR_ACCESS_DENIED,
976 "RegOpenKeyEx failed! result: %08x\n", lResult);
977 if (lResult != ERROR_SUCCESS) {
978 if (lResult == ERROR_ACCESS_DENIED)
979 skip("Not enough rights to open the registry key\n");
980 IMalloc_Free(ppM, pidlMyDocuments);
981 IShellFolder_Release(psfDesktop);
982 return;
985 /* Query MyDocuments' Attributes value, to be able to restore it later. */
986 dwSize = sizeof(DWORD);
987 lResult = RegQueryValueExW(hKey, wszAttributes, NULL, NULL, (LPBYTE)&dwOrigAttributes, &dwSize);
988 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
989 if (lResult != ERROR_SUCCESS) {
990 RegCloseKey(hKey);
991 IMalloc_Free(ppM, pidlMyDocuments);
992 IShellFolder_Release(psfDesktop);
993 return;
996 /* Query MyDocuments' CallForAttributes value, to be able to restore it later. */
997 dwSize = sizeof(DWORD);
998 lResult = RegQueryValueExW(hKey, wszCallForAttributes, NULL, NULL,
999 (LPBYTE)&dwOrigCallForAttributes, &dwSize);
1000 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
1001 if (lResult != ERROR_SUCCESS) {
1002 RegCloseKey(hKey);
1003 IMalloc_Free(ppM, pidlMyDocuments);
1004 IShellFolder_Release(psfDesktop);
1005 return;
1008 /* Define via the Attributes value that MyDocuments attributes are SFGAO_ISSLOW and
1009 * SFGAO_GHOSTED and that MyDocuments should be called for the SFGAO_ISSLOW and
1010 * SFGAO_FILESYSTEM attributes. */
1011 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED;
1012 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwAttributes, sizeof(DWORD));
1013 dwCallForAttributes = SFGAO_ISSLOW|SFGAO_FILESYSTEM;
1014 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
1015 (LPBYTE)&dwCallForAttributes, sizeof(DWORD));
1017 /* Although it is not set in CallForAttributes, the SFGAO_GHOSTED flag is reset by
1018 * GetAttributesOf. It seems that once there is a single attribute queried, for which
1019 * CallForAttributes is set, all flags are taken from the GetAttributesOf call and
1020 * the flags in Attributes are ignored.
1022 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED|SFGAO_FILESYSTEM;
1023 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
1024 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
1025 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
1026 if (hr == S_OK)
1027 ok (dwAttributes == SFGAO_FILESYSTEM,
1028 "Desktop->GetAttributes(MyDocuments) returned unexpected attributes: %08x\n",
1029 dwAttributes);
1031 /* Restore MyDocuments' original Attributes and CallForAttributes registry values */
1032 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwOrigAttributes, sizeof(DWORD));
1033 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
1034 (LPBYTE)&dwOrigCallForAttributes, sizeof(DWORD));
1035 RegCloseKey(hKey);
1036 IMalloc_Free(ppM, pidlMyDocuments);
1037 IShellFolder_Release(psfDesktop);
1040 static void test_GetAttributesOf(void)
1042 HRESULT hr;
1043 LPSHELLFOLDER psfDesktop, psfMyComputer;
1044 SHITEMID emptyitem = { 0, { 0 } };
1045 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
1046 LPITEMIDLIST pidlMyComputer;
1047 DWORD dwFlags;
1048 static const DWORD desktopFlags[] = {
1049 /* WinXP */
1050 SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSANCESTOR |
1051 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
1052 /* Win2k */
1053 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_STREAM | SFGAO_FILESYSANCESTOR |
1054 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
1055 /* WinMe, Win9x, WinNT*/
1056 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSANCESTOR |
1057 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
1059 static const DWORD myComputerFlags[] = {
1060 /* WinXP */
1061 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
1062 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1063 /* Win2k */
1064 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_STREAM |
1065 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1066 /* WinMe, Win9x, WinNT */
1067 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
1068 SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1069 /* Win95, WinNT when queried directly */
1070 SFGAO_CANLINK | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
1071 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
1073 WCHAR wszMyComputer[] = {
1074 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
1075 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
1076 char cCurrDirA [MAX_PATH] = {0};
1077 WCHAR cCurrDirW [MAX_PATH];
1078 static WCHAR cTestDirW[] = {'t','e','s','t','d','i','r',0};
1079 IShellFolder *IDesktopFolder, *testIShellFolder;
1080 ITEMIDLIST *newPIDL;
1081 int len, i;
1082 BOOL foundFlagsMatch;
1084 hr = SHGetDesktopFolder(&psfDesktop);
1085 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1086 if (hr != S_OK) return;
1088 /* The Desktop attributes can be queried with a single empty itemidlist, .. */
1089 dwFlags = 0xffffffff;
1090 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, &pidlEmpty, &dwFlags);
1091 ok (hr == S_OK, "Desktop->GetAttributesOf(empty pidl) failed! hr = %08x\n", hr);
1092 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1093 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
1095 if (desktopFlags[i] == dwFlags)
1096 foundFlagsMatch = TRUE;
1098 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
1100 /* .. or with no itemidlist at all. */
1101 dwFlags = 0xffffffff;
1102 hr = IShellFolder_GetAttributesOf(psfDesktop, 0, NULL, &dwFlags);
1103 ok (hr == S_OK, "Desktop->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
1104 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1105 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
1107 if (desktopFlags[i] == dwFlags)
1108 foundFlagsMatch = TRUE;
1110 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
1112 /* Testing the attributes of the MyComputer shellfolder */
1113 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1114 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1115 if (hr != S_OK) {
1116 IShellFolder_Release(psfDesktop);
1117 return;
1120 /* Windows sets the SFGAO_CANLINK flag, when MyComputer is queried via the Desktop
1121 * folder object. It doesn't do this, if MyComputer is queried directly (see below).
1123 dwFlags = 0xffffffff;
1124 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, (LPCITEMIDLIST*)&pidlMyComputer, &dwFlags);
1125 ok (hr == S_OK, "Desktop->GetAttributesOf(MyComputer) failed! hr = %08x\n", hr);
1126 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1127 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
1129 if ((myComputerFlags[i] | SFGAO_CANLINK) == dwFlags)
1130 foundFlagsMatch = TRUE;
1132 todo_wine
1133 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
1135 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
1136 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
1137 IShellFolder_Release(psfDesktop);
1138 IMalloc_Free(ppM, pidlMyComputer);
1139 if (hr != S_OK) return;
1141 hr = IShellFolder_GetAttributesOf(psfMyComputer, 1, &pidlEmpty, &dwFlags);
1142 todo_wine
1143 ok (hr == E_INVALIDARG ||
1144 broken(hr == S_OK), /* W2K and earlier */
1145 "MyComputer->GetAttributesOf(emtpy pidl) should fail! hr = %08x\n", hr);
1147 dwFlags = 0xffffffff;
1148 hr = IShellFolder_GetAttributesOf(psfMyComputer, 0, NULL, &dwFlags);
1149 ok (hr == S_OK, "MyComputer->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
1150 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1151 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
1153 if (myComputerFlags[i] == dwFlags)
1154 foundFlagsMatch = TRUE;
1156 todo_wine
1157 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
1159 IShellFolder_Release(psfMyComputer);
1161 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1162 len = lstrlenA(cCurrDirA);
1164 if (len == 0) {
1165 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_GetAttributesOf\n");
1166 return;
1168 if (len > 3 && cCurrDirA[len-1] == '\\')
1169 cCurrDirA[len-1] = 0;
1171 /* create test directory */
1172 CreateFilesFolders();
1174 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1176 hr = SHGetDesktopFolder(&IDesktopFolder);
1177 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1179 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1180 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1182 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1183 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1185 IMalloc_Free(ppM, newPIDL);
1187 /* get relative PIDL */
1188 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1189 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1191 /* test the shell attributes of the test directory using the relative PIDL */
1192 dwFlags = SFGAO_FOLDER;
1193 hr = IShellFolder_GetAttributesOf(testIShellFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
1194 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
1195 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for relative PIDL: %08x\n", dwFlags);
1197 /* free memory */
1198 IMalloc_Free(ppM, newPIDL);
1200 /* append testdirectory name to path */
1201 if (cCurrDirA[len-1] == '\\')
1202 cCurrDirA[len-1] = 0;
1203 lstrcatA(cCurrDirA, "\\testdir");
1204 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1206 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1207 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1209 /* test the shell attributes of the test directory using the absolute PIDL */
1210 dwFlags = SFGAO_FOLDER;
1211 hr = IShellFolder_GetAttributesOf(IDesktopFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
1212 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
1213 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for absolute PIDL: %08x\n", dwFlags);
1215 /* free memory */
1216 IMalloc_Free(ppM, newPIDL);
1218 IShellFolder_Release(testIShellFolder);
1220 Cleanup();
1222 IShellFolder_Release(IDesktopFolder);
1225 static void test_SHGetPathFromIDList(void)
1227 SHITEMID emptyitem = { 0, { 0 } };
1228 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
1229 LPITEMIDLIST pidlMyComputer;
1230 WCHAR wszPath[MAX_PATH], wszDesktop[MAX_PATH];
1231 BOOL result;
1232 HRESULT hr;
1233 LPSHELLFOLDER psfDesktop;
1234 WCHAR wszMyComputer[] = {
1235 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
1236 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
1237 WCHAR wszFileName[MAX_PATH];
1238 LPITEMIDLIST pidlTestFile;
1239 HANDLE hTestFile;
1240 STRRET strret;
1241 static WCHAR wszTestFile[] = {
1242 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
1243 LPITEMIDLIST pidlPrograms;
1245 if(!pSHGetPathFromIDListW || !pSHGetSpecialFolderPathW)
1247 win_skip("SHGetPathFromIDListW() or SHGetSpecialFolderPathW() is missing\n");
1248 return;
1251 /* Calling SHGetPathFromIDListW with no pidl should return the empty string */
1252 wszPath[0] = 'a';
1253 wszPath[1] = '\0';
1254 result = pSHGetPathFromIDListW(NULL, wszPath);
1255 ok(!result, "Expected failure\n");
1256 ok(!wszPath[0], "Expected empty string\n");
1258 /* Calling SHGetPathFromIDListW with an empty pidl should return the desktop folder's path. */
1259 result = pSHGetSpecialFolderPathW(NULL, wszDesktop, CSIDL_DESKTOP, FALSE);
1260 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOP) failed! Last error: %u\n", GetLastError());
1261 if (!result) return;
1263 /* Check if we are on Win9x */
1264 SetLastError(0xdeadbeef);
1265 lstrcmpiW(wszDesktop, wszDesktop);
1266 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1268 win_skip("Most W-calls are not implemented\n");
1269 return;
1272 result = pSHGetPathFromIDListW(pidlEmpty, wszPath);
1273 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1274 if (!result) return;
1275 ok(!lstrcmpiW(wszDesktop, wszPath), "SHGetPathFromIDListW didn't return desktop path for empty pidl!\n");
1277 /* MyComputer does not map to a filesystem path. SHGetPathFromIDListW should fail. */
1278 hr = SHGetDesktopFolder(&psfDesktop);
1279 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1280 if (hr != S_OK) return;
1282 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1283 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1284 if (hr != S_OK) {
1285 IShellFolder_Release(psfDesktop);
1286 return;
1289 SetLastError(0xdeadbeef);
1290 wszPath[0] = 'a';
1291 wszPath[1] = '\0';
1292 result = pSHGetPathFromIDListW(pidlMyComputer, wszPath);
1293 ok (!result, "SHGetPathFromIDListW succeeded where it shouldn't!\n");
1294 ok (GetLastError()==0xdeadbeef ||
1295 GetLastError()==ERROR_SUCCESS, /* Vista and higher */
1296 "Unexpected last error from SHGetPathFromIDListW: %u\n", GetLastError());
1297 ok (!wszPath[0], "Expected empty path\n");
1298 if (result) {
1299 IShellFolder_Release(psfDesktop);
1300 return;
1303 IMalloc_Free(ppM, pidlMyComputer);
1305 result = pSHGetSpecialFolderPathW(NULL, wszFileName, CSIDL_DESKTOPDIRECTORY, FALSE);
1306 ok(result, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1307 if (!result) {
1308 IShellFolder_Release(psfDesktop);
1309 return;
1311 myPathAddBackslashW(wszFileName);
1312 lstrcatW(wszFileName, wszTestFile);
1313 hTestFile = CreateFileW(wszFileName, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
1314 ok(hTestFile != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: %u\n", GetLastError());
1315 if (hTestFile == INVALID_HANDLE_VALUE) {
1316 IShellFolder_Release(psfDesktop);
1317 return;
1319 CloseHandle(hTestFile);
1321 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
1322 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse filename hr = %08x\n", hr);
1323 if (hr != S_OK) {
1324 IShellFolder_Release(psfDesktop);
1325 DeleteFileW(wszFileName);
1326 IMalloc_Free(ppM, pidlTestFile);
1327 return;
1330 /* This test is to show that the Desktop shellfolder prepends the CSIDL_DESKTOPDIRECTORY
1331 * path for files placed on the desktop, if called with SHGDN_FORPARSING. */
1332 hr = IShellFolder_GetDisplayNameOf(psfDesktop, pidlTestFile, SHGDN_FORPARSING, &strret);
1333 ok (hr == S_OK, "Desktop's GetDisplayNamfOf failed! hr = %08x\n", hr);
1334 IShellFolder_Release(psfDesktop);
1335 DeleteFileW(wszFileName);
1336 if (hr != S_OK) {
1337 IMalloc_Free(ppM, pidlTestFile);
1338 return;
1340 if (pStrRetToBufW)
1342 pStrRetToBufW(&strret, pidlTestFile, wszPath, MAX_PATH);
1343 ok(0 == lstrcmpW(wszFileName, wszPath),
1344 "Desktop->GetDisplayNameOf(pidlTestFile, SHGDN_FORPARSING) "
1345 "returned incorrect path for file placed on desktop\n");
1348 result = pSHGetPathFromIDListW(pidlTestFile, wszPath);
1349 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1350 IMalloc_Free(ppM, pidlTestFile);
1351 if (!result) return;
1352 ok(0 == lstrcmpW(wszFileName, wszPath), "SHGetPathFromIDListW returned incorrect path for file placed on desktop\n");
1355 /* Test if we can get the path from the start menu "program files" PIDL. */
1356 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidlPrograms);
1357 ok(hr == S_OK, "SHGetFolderLocation failed: 0x%08x\n", hr);
1359 SetLastError(0xdeadbeef);
1360 result = pSHGetPathFromIDListW(pidlPrograms, wszPath);
1361 IMalloc_Free(ppM, pidlPrograms);
1362 ok(result, "SHGetPathFromIDListW failed\n");
1365 static void test_EnumObjects_and_CompareIDs(void)
1367 ITEMIDLIST *newPIDL;
1368 IShellFolder *IDesktopFolder, *testIShellFolder;
1369 char cCurrDirA [MAX_PATH] = {0};
1370 static const CHAR cTestDirA[] = "\\testdir";
1371 WCHAR cTestDirW[MAX_PATH];
1372 int len;
1373 HRESULT hr;
1375 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1376 len = lstrlenA(cCurrDirA);
1378 if(len == 0) {
1379 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_EnumObjects_and_CompareIDs\n");
1380 return;
1382 if(cCurrDirA[len-1] == '\\')
1383 cCurrDirA[len-1] = 0;
1385 lstrcatA(cCurrDirA, cTestDirA);
1386 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cTestDirW, MAX_PATH);
1388 hr = SHGetDesktopFolder(&IDesktopFolder);
1389 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1391 CreateFilesFolders();
1393 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1394 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1396 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1397 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1399 test_EnumObjects(testIShellFolder);
1401 IShellFolder_Release(testIShellFolder);
1403 Cleanup();
1405 IMalloc_Free(ppM, newPIDL);
1407 IShellFolder_Release(IDesktopFolder);
1410 /* A simple implementation of an IPropertyBag, which returns fixed values for
1411 * 'Target' and 'Attributes' properties.
1413 static HRESULT WINAPI InitPropertyBag_IPropertyBag_QueryInterface(IPropertyBag *iface, REFIID riid,
1414 void **ppvObject)
1416 if (!ppvObject)
1417 return E_INVALIDARG;
1419 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPropertyBag, riid)) {
1420 *ppvObject = iface;
1421 } else {
1422 ok (FALSE, "InitPropertyBag asked for unknown interface!\n");
1423 return E_NOINTERFACE;
1426 IPropertyBag_AddRef(iface);
1427 return S_OK;
1430 static ULONG WINAPI InitPropertyBag_IPropertyBag_AddRef(IPropertyBag *iface) {
1431 return 2;
1434 static ULONG WINAPI InitPropertyBag_IPropertyBag_Release(IPropertyBag *iface) {
1435 return 1;
1438 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Read(IPropertyBag *iface, LPCOLESTR pszPropName,
1439 VARIANT *pVar, IErrorLog *pErrorLog)
1441 static const WCHAR wszTargetSpecialFolder[] = {
1442 'T','a','r','g','e','t','S','p','e','c','i','a','l','F','o','l','d','e','r',0 };
1443 static const WCHAR wszTarget[] = {
1444 'T','a','r','g','e','t',0 };
1445 static const WCHAR wszAttributes[] = {
1446 'A','t','t','r','i','b','u','t','e','s',0 };
1447 static const WCHAR wszResolveLinkFlags[] = {
1448 'R','e','s','o','l','v','e','L','i','n','k','F','l','a','g','s',0 };
1449 static const WCHAR wszTargetKnownFolder[] = {
1450 'T','a','r','g','e','t','K','n','o','w','n','F','o','l','d','e','r',0 };
1451 static const WCHAR wszCLSID[] = {
1452 'C','L','S','I','D',0 };
1454 if (!lstrcmpW(pszPropName, wszTargetSpecialFolder)) {
1455 ok(V_VT(pVar) == VT_I4 ||
1456 broken(V_VT(pVar) == VT_BSTR), /* Win2k */
1457 "Wrong variant type for 'TargetSpecialFolder' property!\n");
1458 return E_INVALIDARG;
1461 if (!lstrcmpW(pszPropName, wszResolveLinkFlags))
1463 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'ResolveLinkFlags' property!\n");
1464 return E_INVALIDARG;
1467 if (!lstrcmpW(pszPropName, wszTarget)) {
1468 WCHAR wszPath[MAX_PATH];
1469 BOOL result;
1471 ok(V_VT(pVar) == VT_BSTR ||
1472 broken(V_VT(pVar) == VT_EMPTY), /* Win2k */
1473 "Wrong variant type for 'Target' property!\n");
1474 if (V_VT(pVar) != VT_BSTR) return E_INVALIDARG;
1476 result = pSHGetSpecialFolderPathW(NULL, wszPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1477 ok(result, "SHGetSpecialFolderPathW(DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1478 if (!result) return E_INVALIDARG;
1480 V_BSTR(pVar) = SysAllocString(wszPath);
1481 return S_OK;
1484 if (!lstrcmpW(pszPropName, wszAttributes)) {
1485 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'Attributes' property!\n");
1486 if (V_VT(pVar) != VT_UI4) return E_INVALIDARG;
1487 V_UI4(pVar) = SFGAO_FOLDER|SFGAO_HASSUBFOLDER|SFGAO_FILESYSANCESTOR|
1488 SFGAO_CANRENAME|SFGAO_FILESYSTEM;
1489 return S_OK;
1492 if (!lstrcmpW(pszPropName, wszTargetKnownFolder)) {
1493 ok(V_VT(pVar) == VT_BSTR, "Wrong variant type for 'TargetKnownFolder' property!\n");
1494 /* TODO */
1495 return E_INVALIDARG;
1498 if (!lstrcmpW(pszPropName, wszCLSID)) {
1499 ok(V_VT(pVar) == VT_EMPTY, "Wrong variant type for 'CLSID' property!\n");
1500 /* TODO */
1501 return E_INVALIDARG;
1504 ok(FALSE, "PropertyBag was asked for unknown property %s (vt=%d)!\n", wine_dbgstr_w(pszPropName), V_VT(pVar));
1505 return E_INVALIDARG;
1508 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Write(IPropertyBag *iface, LPCOLESTR pszPropName,
1509 VARIANT *pVar)
1511 ok(FALSE, "Unexpected call to IPropertyBag_Write\n");
1512 return E_NOTIMPL;
1515 static const IPropertyBagVtbl InitPropertyBag_IPropertyBagVtbl = {
1516 InitPropertyBag_IPropertyBag_QueryInterface,
1517 InitPropertyBag_IPropertyBag_AddRef,
1518 InitPropertyBag_IPropertyBag_Release,
1519 InitPropertyBag_IPropertyBag_Read,
1520 InitPropertyBag_IPropertyBag_Write
1523 static struct IPropertyBag InitPropertyBag = {
1524 &InitPropertyBag_IPropertyBagVtbl
1527 static void test_FolderShortcut(void) {
1528 IPersistPropertyBag *pPersistPropertyBag;
1529 IShellFolder *pShellFolder, *pDesktopFolder;
1530 IPersistFolder3 *pPersistFolder3;
1531 HRESULT hr;
1532 STRRET strret;
1533 WCHAR wszDesktopPath[MAX_PATH], wszBuffer[MAX_PATH];
1534 BOOL result;
1535 CLSID clsid;
1536 LPITEMIDLIST pidlCurrentFolder, pidlWineTestFolder, pidlSubFolder;
1537 HKEY hShellExtKey;
1538 WCHAR wszWineTestFolder[] = {
1539 ':',':','{','9','B','3','5','2','E','B','F','-','2','7','6','5','-','4','5','C','1','-',
1540 'B','4','C','6','-','8','5','C','C','7','F','7','A','B','C','6','4','}',0 };
1541 WCHAR wszShellExtKey[] = { 'S','o','f','t','w','a','r','e','\\',
1542 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
1543 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1544 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
1545 'N','a','m','e','S','p','a','c','e','\\',
1546 '{','9','b','3','5','2','e','b','f','-','2','7','6','5','-','4','5','c','1','-',
1547 'b','4','c','6','-','8','5','c','c','7','f','7','a','b','c','6','4','}',0 };
1549 WCHAR wszSomeSubFolder[] = { 'S','u','b','F','o','l','d','e','r', 0};
1550 static const GUID CLSID_UnixDosFolder =
1551 {0x9d20aae8, 0x0625, 0x44b0, {0x9c, 0xa7, 0x71, 0x88, 0x9c, 0x22, 0x54, 0xd9}};
1553 if (!pSHGetSpecialFolderPathW || !pStrRetToBufW) {
1554 win_skip("SHGetSpecialFolderPathW and/or StrRetToBufW are not available\n");
1555 return;
1558 if (!pSHGetFolderPathAndSubDirA)
1560 win_skip("FolderShortcut test doesn't work on Win2k\n");
1561 return;
1564 /* These tests basically show, that CLSID_FolderShortcuts are initialized
1565 * via their IPersistPropertyBag interface. And that the target folder
1566 * is taken from the IPropertyBag's 'Target' property.
1568 hr = CoCreateInstance(&CLSID_FolderShortcut, NULL, CLSCTX_INPROC_SERVER,
1569 &IID_IPersistPropertyBag, (LPVOID*)&pPersistPropertyBag);
1570 if (hr == REGDB_E_CLASSNOTREG) {
1571 win_skip("CLSID_FolderShortcut is not implemented\n");
1572 return;
1574 ok (hr == S_OK, "CoCreateInstance failed! hr = 0x%08x\n", hr);
1575 if (hr != S_OK) return;
1577 hr = IPersistPropertyBag_Load(pPersistPropertyBag, &InitPropertyBag, NULL);
1578 ok(hr == S_OK, "IPersistPropertyBag_Load failed! hr = %08x\n", hr);
1579 if (hr != S_OK) {
1580 IPersistPropertyBag_Release(pPersistPropertyBag);
1581 return;
1584 hr = IPersistPropertyBag_QueryInterface(pPersistPropertyBag, &IID_IShellFolder,
1585 (LPVOID*)&pShellFolder);
1586 IPersistPropertyBag_Release(pPersistPropertyBag);
1587 ok(hr == S_OK, "IPersistPropertyBag_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1588 if (hr != S_OK) return;
1590 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1591 ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1592 if (hr != S_OK) {
1593 IShellFolder_Release(pShellFolder);
1594 return;
1597 result = pSHGetSpecialFolderPathW(NULL, wszDesktopPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1598 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1599 if (!result) return;
1601 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1602 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1604 hr = IShellFolder_QueryInterface(pShellFolder, &IID_IPersistFolder3, (LPVOID*)&pPersistFolder3);
1605 IShellFolder_Release(pShellFolder);
1606 ok(hr == S_OK, "IShellFolder_QueryInterface(IID_IPersistFolder3 failed! hr = 0x%08x\n", hr);
1607 if (hr != S_OK) return;
1609 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1610 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1611 ok(IsEqualCLSID(&clsid, &CLSID_FolderShortcut), "Unexpected CLSID!\n");
1613 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1614 todo_wine ok(hr == S_FALSE, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1615 ok(!pidlCurrentFolder, "IPersistFolder3_GetCurFolder should return a NULL pidl!\n");
1617 /* For FolderShortcut objects, the Initialize method initialized the folder's position in the
1618 * shell namespace. The target folder, read from the property bag above, remains untouched.
1619 * The following tests show this: The itemidlist for some imaginary shellfolder object
1620 * is created and the FolderShortcut is initialized with it. GetCurFolder now returns this
1621 * itemidlist, but GetDisplayNameOf still returns the path from above.
1623 hr = SHGetDesktopFolder(&pDesktopFolder);
1624 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1625 if (hr != S_OK) return;
1627 /* Temporarily register WineTestFolder as a shell namespace extension at the Desktop.
1628 * Otherwise ParseDisplayName fails on WinXP with E_INVALIDARG */
1629 RegCreateKeyW(HKEY_CURRENT_USER, wszShellExtKey, &hShellExtKey);
1630 RegCloseKey(hShellExtKey);
1631 hr = IShellFolder_ParseDisplayName(pDesktopFolder, NULL, NULL, wszWineTestFolder, NULL,
1632 &pidlWineTestFolder, NULL);
1633 RegDeleteKeyW(HKEY_CURRENT_USER, wszShellExtKey);
1634 IShellFolder_Release(pDesktopFolder);
1635 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1636 if (hr != S_OK) return;
1638 hr = IPersistFolder3_Initialize(pPersistFolder3, pidlWineTestFolder);
1639 ok (hr == S_OK, "IPersistFolder3::Initialize failed! hr = %08x\n", hr);
1640 if (hr != S_OK) {
1641 IPersistFolder3_Release(pPersistFolder3);
1642 pILFree(pidlWineTestFolder);
1643 return;
1646 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1647 ok(hr == S_OK, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1648 ok(pILIsEqual(pidlCurrentFolder, pidlWineTestFolder),
1649 "IPersistFolder3_GetCurFolder should return pidlWineTestFolder!\n");
1650 pILFree(pidlCurrentFolder);
1651 pILFree(pidlWineTestFolder);
1653 hr = IPersistFolder3_QueryInterface(pPersistFolder3, &IID_IShellFolder, (LPVOID*)&pShellFolder);
1654 IPersistFolder3_Release(pPersistFolder3);
1655 ok(hr == S_OK, "IPersistFolder3_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1656 if (hr != S_OK) return;
1658 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1659 ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1660 if (hr != S_OK) {
1661 IShellFolder_Release(pShellFolder);
1662 return;
1665 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1666 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1668 /* Next few lines are meant to show that children of FolderShortcuts are not FolderShortcuts,
1669 * but ShellFSFolders. */
1670 myPathAddBackslashW(wszDesktopPath);
1671 lstrcatW(wszDesktopPath, wszSomeSubFolder);
1672 if (!CreateDirectoryW(wszDesktopPath, NULL)) {
1673 IShellFolder_Release(pShellFolder);
1674 return;
1677 hr = IShellFolder_ParseDisplayName(pShellFolder, NULL, NULL, wszSomeSubFolder, NULL,
1678 &pidlSubFolder, NULL);
1679 RemoveDirectoryW(wszDesktopPath);
1680 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1681 if (hr != S_OK) {
1682 IShellFolder_Release(pShellFolder);
1683 return;
1686 hr = IShellFolder_BindToObject(pShellFolder, pidlSubFolder, NULL, &IID_IPersistFolder3,
1687 (LPVOID*)&pPersistFolder3);
1688 IShellFolder_Release(pShellFolder);
1689 pILFree(pidlSubFolder);
1690 ok (hr == S_OK, "IShellFolder::BindToObject failed! hr = %08x\n", hr);
1691 if (hr != S_OK)
1692 return;
1694 /* On windows, we expect CLSID_ShellFSFolder. On wine we relax this constraint
1695 * a little bit and also allow CLSID_UnixDosFolder. */
1696 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1697 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1698 ok(IsEqualCLSID(&clsid, &CLSID_ShellFSFolder) || IsEqualCLSID(&clsid, &CLSID_UnixDosFolder),
1699 "IPersistFolder3::GetClassID returned unexpected CLSID!\n");
1701 IPersistFolder3_Release(pPersistFolder3);
1704 #include "pshpack1.h"
1705 struct FileStructA {
1706 BYTE type;
1707 BYTE dummy;
1708 DWORD dwFileSize;
1709 WORD uFileDate; /* In our current implementation this is */
1710 WORD uFileTime; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastWriteTime) */
1711 WORD uFileAttribs;
1712 CHAR szName[1];
1715 struct FileStructW {
1716 WORD cbLen; /* Length of this element. */
1717 BYTE abFooBar1[6]; /* Beyond any recognition. */
1718 WORD uDate; /* FileTimeToDosDate(WIN32_FIND_DATA->ftCreationTime)? */
1719 WORD uTime; /* (this is currently speculation) */
1720 WORD uDate2; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastAccessTime)? */
1721 WORD uTime2; /* (this is currently speculation) */
1722 BYTE abFooBar2[4]; /* Beyond any recognition. */
1723 WCHAR wszName[1]; /* The long filename in unicode. */
1724 /* Just for documentation: Right after the unicode string: */
1725 WORD cbOffset; /* FileStructW's offset from the beginning of the SHITMEID.
1726 * SHITEMID->cb == uOffset + cbLen */
1728 #include "poppack.h"
1730 static void test_ITEMIDLIST_format(void) {
1731 WCHAR wszPersonal[MAX_PATH];
1732 LPSHELLFOLDER psfDesktop, psfPersonal;
1733 LPITEMIDLIST pidlPersonal, pidlFile;
1734 HANDLE hFile;
1735 HRESULT hr;
1736 BOOL bResult;
1737 WCHAR wszFile[3][17] = { { 'e','v','e','n','_',0 }, { 'o','d','d','_',0 },
1738 { 'l','o','n','g','e','r','_','t','h','a','n','.','8','_','3',0 } };
1739 int i;
1741 if (!pSHGetSpecialFolderPathW) return;
1743 bResult = pSHGetSpecialFolderPathW(NULL, wszPersonal, CSIDL_PERSONAL, FALSE);
1744 ok(bResult, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1745 if (!bResult) return;
1747 SetLastError(0xdeadbeef);
1748 bResult = SetCurrentDirectoryW(wszPersonal);
1749 if (!bResult && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
1750 win_skip("Most W-calls are not implemented\n");
1751 return;
1753 ok(bResult, "SetCurrentDirectory failed! Last error: %u\n", GetLastError());
1754 if (!bResult) return;
1756 hr = SHGetDesktopFolder(&psfDesktop);
1757 ok(hr == S_OK, "SHGetDesktopFolder failed! hr: %08x\n", hr);
1758 if (hr != S_OK) return;
1760 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszPersonal, NULL, &pidlPersonal, NULL);
1761 ok(hr == S_OK, "psfDesktop->ParseDisplayName failed! hr = %08x\n", hr);
1762 if (hr != S_OK) {
1763 IShellFolder_Release(psfDesktop);
1764 return;
1767 hr = IShellFolder_BindToObject(psfDesktop, pidlPersonal, NULL, &IID_IShellFolder,
1768 (LPVOID*)&psfPersonal);
1769 IShellFolder_Release(psfDesktop);
1770 pILFree(pidlPersonal);
1771 ok(hr == S_OK, "psfDesktop->BindToObject failed! hr = %08x\n", hr);
1772 if (hr != S_OK) return;
1774 for (i=0; i<3; i++) {
1775 CHAR szFile[MAX_PATH];
1776 struct FileStructA *pFileStructA;
1777 WORD cbOffset;
1779 WideCharToMultiByte(CP_ACP, 0, wszFile[i], -1, szFile, MAX_PATH, NULL, NULL);
1781 hFile = CreateFileW(wszFile[i], GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_FLAG_WRITE_THROUGH, NULL);
1782 ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed! (%u)\n", GetLastError());
1783 if (hFile == INVALID_HANDLE_VALUE) {
1784 IShellFolder_Release(psfPersonal);
1785 return;
1787 CloseHandle(hFile);
1789 hr = IShellFolder_ParseDisplayName(psfPersonal, NULL, NULL, wszFile[i], NULL, &pidlFile, NULL);
1790 DeleteFileW(wszFile[i]);
1791 ok(hr == S_OK, "psfPersonal->ParseDisplayName failed! hr: %08x\n", hr);
1792 if (hr != S_OK) {
1793 IShellFolder_Release(psfPersonal);
1794 return;
1797 pFileStructA = (struct FileStructA *)pidlFile->mkid.abID;
1798 ok(pFileStructA->type == 0x32, "PIDLTYPE should be 0x32!\n");
1799 ok(pFileStructA->dummy == 0x00, "Dummy Byte should be 0x00!\n");
1800 ok(pFileStructA->dwFileSize == 0, "Filesize should be zero!\n");
1802 if (i < 2) /* First two file names are already in valid 8.3 format */
1803 ok(!strcmp(szFile, (CHAR*)&pidlFile->mkid.abID[12]), "Wrong file name!\n");
1804 else
1805 /* WinXP stores a derived 8.3 dos name (LONGER~1.8_3) here. We probably
1806 * can't implement this correctly, since unix filesystems don't support
1807 * this nasty short/long filename stuff. So we'll probably stay with our
1808 * current habit of storing the long filename here, which seems to work
1809 * just fine. */
1810 todo_wine
1811 ok(pidlFile->mkid.abID[18] == '~' ||
1812 broken(pidlFile->mkid.abID[34] == '~'), /* Win2k */
1813 "Should be derived 8.3 name!\n");
1815 if (i == 0) /* First file name has an even number of chars. No need for alignment. */
1816 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] != '\0' ||
1817 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1), /* Win2k */
1818 "Alignment byte, where there shouldn't be!\n");
1820 if (i == 1) /* Second file name has an uneven number of chars => alignment byte */
1821 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] == '\0',
1822 "There should be an alignment byte, but isn't!\n");
1824 /* The offset of the FileStructW member is stored as a WORD at the end of the pidl. */
1825 cbOffset = *(WORD*)(((LPBYTE)pidlFile)+pidlFile->mkid.cb-sizeof(WORD));
1826 ok ((cbOffset >= sizeof(struct FileStructA) &&
1827 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW)) ||
1828 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1) || /* Win2k on short names */
1829 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 12 + 1), /* Win2k on long names */
1830 "Wrong offset value (%d) stored at the end of the PIDL\n", cbOffset);
1832 if (cbOffset >= sizeof(struct FileStructA) &&
1833 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW))
1835 struct FileStructW *pFileStructW = (struct FileStructW *)(((LPBYTE)pidlFile)+cbOffset);
1836 WCHAR *name = pFileStructW->wszName;
1838 ok(pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen,
1839 "FileStructW's offset and length should add up to the PIDL's length!\n");
1841 if (pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen) {
1842 /* Since we just created the file, time of creation,
1843 * time of last access and time of last write access just be the same.
1844 * These tests seem to fail sometimes (on WinXP), if the test is run again shortly
1845 * after the first run. I do remember something with NTFS keeping the creation time
1846 * if a file is deleted and then created again within a couple of seconds or so.
1847 * Might be the reason. */
1848 ok (pFileStructA->uFileDate == pFileStructW->uDate &&
1849 pFileStructA->uFileTime == pFileStructW->uTime,
1850 "Last write time should match creation time!\n");
1852 /* On FAT filesystems the last access time is midnight
1853 local time, so the values of uDate2 and uTime2 will
1854 depend on the local timezone. If the times are exactly
1855 equal then the dates should be identical for both FAT
1856 and NTFS as no timezone is more than 1 day away from UTC.
1858 if (pFileStructA->uFileTime == pFileStructW->uTime2)
1860 ok (pFileStructA->uFileDate == pFileStructW->uDate2,
1861 "Last write date and time should match last access date and time!\n");
1863 else
1865 /* Filesystem may be FAT. Check date within 1 day
1866 and seconds are zero. */
1867 trace ("Filesystem may be FAT. Performing less strict atime test.\n");
1868 ok ((pFileStructW->uTime2 & 0x1F) == 0,
1869 "Last access time on FAT filesystems should have zero seconds.\n");
1870 /* TODO: Perform check for date being within one day.*/
1873 ok (!lstrcmpW(wszFile[i], name) ||
1874 !lstrcmpW(wszFile[i], name + 9) || /* Vista */
1875 !lstrcmpW(wszFile[i], name + 11) || /* Win7 */
1876 !lstrcmpW(wszFile[i], name + 13), /* Win8 */
1877 "The filename should be stored in unicode at this position!\n");
1881 pILFree(pidlFile);
1884 IShellFolder_Release(psfPersonal);
1887 static void test_SHGetFolderPathA(void)
1889 static const BOOL is_win64 = sizeof(void *) > sizeof(int);
1890 BOOL is_wow64;
1891 char path[MAX_PATH];
1892 char path_x86[MAX_PATH];
1893 char path_key[MAX_PATH];
1894 HRESULT hr;
1895 HKEY key;
1897 if (!pSHGetFolderPathA)
1899 win_skip("SHGetFolderPathA not present\n");
1900 return;
1902 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
1904 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES, 0, SHGFP_TYPE_CURRENT, path );
1905 ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr );
1906 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILESX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
1907 if (hr == E_FAIL)
1909 win_skip( "Program Files (x86) not supported\n" );
1910 return;
1912 ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr );
1913 if (is_win64)
1915 ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1916 ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1917 ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1919 else
1921 ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1922 if (is_wow64)
1923 ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1924 else
1925 ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1927 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1929 DWORD type, count = sizeof(path_x86);
1930 if (!RegQueryValueExA( key, "ProgramFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1932 ok( is_win64 || is_wow64, "ProgramFilesDir (x86) exists on 32-bit setup\n" );
1933 ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1935 else ok( !is_win64 && !is_wow64, "ProgramFilesDir (x86) should exist on 64-bit setup\n" );
1936 RegCloseKey( key );
1939 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMON, 0, SHGFP_TYPE_CURRENT, path );
1940 ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr );
1941 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMONX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
1942 if (hr == E_FAIL)
1944 win_skip( "Common Files (x86) not supported\n" );
1945 return;
1947 ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr );
1948 if (is_win64)
1950 ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1951 ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1952 ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1954 else
1956 ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1957 if (is_wow64)
1958 ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1959 else
1960 ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1962 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1964 DWORD type, count = sizeof(path_x86);
1965 if (!RegQueryValueExA( key, "CommonFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1967 ok( is_win64 || is_wow64, "CommonFilesDir (x86) exists on 32-bit setup\n" );
1968 ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1970 else ok( !is_win64 && !is_wow64, "CommonFilesDir (x86) should exist on 64-bit setup\n" );
1974 static void test_SHGetFolderPathAndSubDirA(void)
1976 HRESULT ret;
1977 BOOL delret;
1978 DWORD dwret;
1979 int i;
1980 static const char wine[] = "wine";
1981 static const char winetemp[] = "wine\\temp";
1982 static char appdata[MAX_PATH];
1983 static char testpath[MAX_PATH];
1984 static char toolongpath[MAX_PATH+1];
1986 if(!pSHGetFolderPathAndSubDirA)
1988 win_skip("SHGetFolderPathAndSubDirA not present!\n");
1989 return;
1992 if(!pSHGetFolderPathA) {
1993 win_skip("SHGetFolderPathA not present!\n");
1994 return;
1996 if(FAILED(pSHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdata)))
1998 win_skip("SHGetFolderPathA failed for CSIDL_LOCAL_APPDATA!\n");
1999 return;
2002 sprintf(testpath, "%s\\%s", appdata, winetemp);
2003 delret = RemoveDirectoryA(testpath);
2004 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) ) {
2005 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
2006 return;
2009 sprintf(testpath, "%s\\%s", appdata, wine);
2010 delret = RemoveDirectoryA(testpath);
2011 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) && (ERROR_FILE_NOT_FOUND != GetLastError())) {
2012 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
2013 return;
2016 /* test invalid second parameter */
2017 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | 0xff, NULL, SHGFP_TYPE_CURRENT, wine, testpath);
2018 ok(E_INVALIDARG == ret, "expected E_INVALIDARG, got %x\n", ret);
2020 /* test fourth parameter */
2021 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, 2, winetemp, testpath);
2022 switch(ret) {
2023 case S_OK: /* winvista */
2024 ok(!strncmp(appdata, testpath, strlen(appdata)),
2025 "expected %s to start with %s\n", testpath, appdata);
2026 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
2027 "expected %s to end with %s\n", testpath, winetemp);
2028 break;
2029 case E_INVALIDARG: /* winxp, win2k3 */
2030 break;
2031 default:
2032 ok(0, "expected S_OK or E_INVALIDARG, got %x\n", ret);
2035 /* test fifth parameter */
2036 testpath[0] = '\0';
2037 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, NULL, testpath);
2038 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2039 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2041 testpath[0] = '\0';
2042 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "", testpath);
2043 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2044 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2046 testpath[0] = '\0';
2047 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "\\", testpath);
2048 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2049 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2051 for(i=0; i< MAX_PATH; i++)
2052 toolongpath[i] = '0' + i % 10;
2053 toolongpath[MAX_PATH] = '\0';
2054 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, toolongpath, testpath);
2055 ok(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) == ret,
2056 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), ret);
2058 testpath[0] = '\0';
2059 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wine, NULL);
2060 ok((S_OK == ret) || (E_INVALIDARG == ret), "expected S_OK or E_INVALIDARG, got %x\n", ret);
2062 /* test a not existing path */
2063 testpath[0] = '\0';
2064 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
2065 ok(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == ret,
2066 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), ret);
2068 /* create a directory inside a not existing directory */
2069 testpath[0] = '\0';
2070 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_CREATE | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
2071 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2072 ok(!strncmp(appdata, testpath, strlen(appdata)),
2073 "expected %s to start with %s\n", testpath, appdata);
2074 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
2075 "expected %s to end with %s\n", testpath, winetemp);
2076 dwret = GetFileAttributesA(testpath);
2077 ok(FILE_ATTRIBUTE_DIRECTORY | dwret, "expected %x to contain FILE_ATTRIBUTE_DIRECTORY\n", dwret);
2079 /* cleanup */
2080 sprintf(testpath, "%s\\%s", appdata, winetemp);
2081 RemoveDirectoryA(testpath);
2082 sprintf(testpath, "%s\\%s", appdata, wine);
2083 RemoveDirectoryA(testpath);
2086 static void test_LocalizedNames(void)
2088 static char cCurrDirA[MAX_PATH];
2089 WCHAR cCurrDirW[MAX_PATH], tempbufW[25];
2090 IShellFolder *IDesktopFolder, *testIShellFolder;
2091 ITEMIDLIST *newPIDL;
2092 int len;
2093 HRESULT hr;
2094 static char resourcefile[MAX_PATH];
2095 DWORD res;
2096 HANDLE file;
2097 STRRET strret;
2098 BOOL ret;
2100 static const char desktopini_contents1[] =
2101 "[.ShellClassInfo]\r\n"
2102 "LocalizedResourceName=@";
2103 static const char desktopini_contents2[] =
2104 ",-1\r\n";
2105 static WCHAR foldernameW[] = {'t','e','s','t','f','o','l','d','e','r',0};
2106 static const WCHAR folderdisplayW[] = {'F','o','l','d','e','r',' ','N','a','m','e',' ','R','e','s','o','u','r','c','e',0};
2108 /* create folder with desktop.ini and localized name in GetModuleFileNameA(NULL) */
2109 CreateDirectoryA(".\\testfolder", NULL);
2111 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")|FILE_ATTRIBUTE_SYSTEM);
2113 GetModuleFileNameA(NULL, resourcefile, MAX_PATH);
2115 file = CreateFileA(".\\testfolder\\desktop.ini", GENERIC_WRITE, 0, NULL,
2116 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2117 ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %i\n", GetLastError());
2118 ret = WriteFile(file, desktopini_contents1, strlen(desktopini_contents1), &res, NULL) &&
2119 WriteFile(file, resourcefile, strlen(resourcefile), &res, NULL) &&
2120 WriteFile(file, desktopini_contents2, strlen(desktopini_contents2), &res, NULL);
2121 ok(ret, "WriteFile failed %i\n", GetLastError());
2122 CloseHandle(file);
2124 /* get IShellFolder for parent */
2125 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
2126 len = lstrlenA(cCurrDirA);
2128 if (len == 0) {
2129 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_LocalizedNames\n");
2130 goto cleanup;
2132 if(cCurrDirA[len-1] == '\\')
2133 cCurrDirA[len-1] = 0;
2135 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
2137 hr = SHGetDesktopFolder(&IDesktopFolder);
2138 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
2140 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
2141 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
2143 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
2144 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
2146 IMalloc_Free(ppM, newPIDL);
2148 /* windows reads the display name from the resource */
2149 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, foldernameW, NULL, &newPIDL, 0);
2150 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
2152 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER, &strret);
2153 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2155 if (hr == S_OK && pStrRetToBufW)
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));
2165 /* editing name is also read from the resource */
2166 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FOREDITING, &strret);
2167 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2169 if (hr == S_OK && pStrRetToBufW)
2171 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2172 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2173 todo_wine
2174 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
2175 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
2176 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2179 /* parsing name is unchanged */
2180 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FORPARSING, &strret);
2181 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2183 if (hr == S_OK && pStrRetToBufW)
2185 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2186 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2187 ok (!lstrcmpiW(tempbufW, foldernameW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2190 IShellFolder_Release(IDesktopFolder);
2191 IShellFolder_Release(testIShellFolder);
2193 IMalloc_Free(ppM, newPIDL);
2195 cleanup:
2196 DeleteFileA(".\\testfolder\\desktop.ini");
2197 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")&~FILE_ATTRIBUTE_SYSTEM);
2198 RemoveDirectoryA(".\\testfolder");
2201 static void test_SHCreateShellItem(void)
2203 IShellItem *shellitem, *shellitem2;
2204 IPersistIDList *persistidl;
2205 LPITEMIDLIST pidl_cwd=NULL, pidl_testfile, pidl_abstestfile, pidl_test, pidl_desktop;
2206 HRESULT ret;
2207 char curdirA[MAX_PATH];
2208 WCHAR curdirW[MAX_PATH];
2209 WCHAR fnbufW[MAX_PATH];
2210 IShellFolder *desktopfolder=NULL, *currentfolder=NULL;
2211 static WCHAR testfileW[] = {'t','e','s','t','f','i','l','e',0};
2213 GetCurrentDirectoryA(MAX_PATH, curdirA);
2215 if (!pSHCreateShellItem)
2217 win_skip("SHCreateShellItem isn't available\n");
2218 return;
2221 if (!curdirA[0])
2223 win_skip("GetCurrentDirectoryA returned empty string, skipping test_SHCreateShellItem\n");
2224 return;
2227 if(pSHGetSpecialFolderLocation)
2229 ret = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
2230 ok(ret == S_OK, "Got 0x%08x\n", ret);
2232 else
2234 win_skip("pSHGetSpecialFolderLocation missing.\n");
2235 pidl_desktop = NULL;
2238 MultiByteToWideChar(CP_ACP, 0, curdirA, -1, curdirW, MAX_PATH);
2240 ret = SHGetDesktopFolder(&desktopfolder);
2241 ok(SUCCEEDED(ret), "SHGetShellFolder returned %x\n", ret);
2243 ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2244 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2246 ret = IShellFolder_BindToObject(desktopfolder, pidl_cwd, NULL, &IID_IShellFolder, (void**)&currentfolder);
2247 ok(SUCCEEDED(ret), "BindToObject returned %x\n", ret);
2249 CreateTestFile(".\\testfile");
2251 ret = IShellFolder_ParseDisplayName(currentfolder, NULL, NULL, testfileW, NULL, &pidl_testfile, NULL);
2252 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2254 pidl_abstestfile = pILCombine(pidl_cwd, pidl_testfile);
2256 shellitem = (void*)0xdeadbeef;
2257 ret = pSHCreateShellItem(NULL, NULL, NULL, &shellitem);
2258 ok(ret == E_INVALIDARG, "SHCreateShellItem returned %x\n", ret);
2259 ok(shellitem == 0, "Got %p\n", shellitem);
2261 if (0) /* crashes on Windows XP */
2263 pSHCreateShellItem(NULL, NULL, pidl_cwd, NULL);
2264 pSHCreateShellItem(pidl_cwd, NULL, NULL, &shellitem);
2265 pSHCreateShellItem(NULL, currentfolder, NULL, &shellitem);
2266 pSHCreateShellItem(pidl_cwd, currentfolder, NULL, &shellitem);
2269 ret = pSHCreateShellItem(NULL, NULL, pidl_cwd, &shellitem);
2270 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2271 if (SUCCEEDED(ret))
2273 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2274 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2275 if (SUCCEEDED(ret))
2277 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2278 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2279 if (SUCCEEDED(ret))
2281 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2282 pILFree(pidl_test);
2284 IPersistIDList_Release(persistidl);
2286 IShellItem_Release(shellitem);
2289 ret = pSHCreateShellItem(pidl_cwd, NULL, pidl_testfile, &shellitem);
2290 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2291 if (SUCCEEDED(ret))
2293 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2294 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2295 if (SUCCEEDED(ret))
2297 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2298 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2299 if (SUCCEEDED(ret))
2301 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2302 pILFree(pidl_test);
2304 IPersistIDList_Release(persistidl);
2307 ret = IShellItem_GetParent(shellitem, &shellitem2);
2308 ok(SUCCEEDED(ret), "GetParent returned %x\n", ret);
2309 if (SUCCEEDED(ret))
2311 ret = IShellItem_QueryInterface(shellitem2, &IID_IPersistIDList, (void**)&persistidl);
2312 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2313 if (SUCCEEDED(ret))
2315 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2316 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2317 if (SUCCEEDED(ret))
2319 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2320 pILFree(pidl_test);
2322 IPersistIDList_Release(persistidl);
2324 IShellItem_Release(shellitem2);
2327 IShellItem_Release(shellitem);
2330 ret = pSHCreateShellItem(NULL, currentfolder, pidl_testfile, &shellitem);
2331 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2332 if (SUCCEEDED(ret))
2334 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2335 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2336 if (SUCCEEDED(ret))
2338 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2339 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2340 if (SUCCEEDED(ret))
2342 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2343 pILFree(pidl_test);
2345 IPersistIDList_Release(persistidl);
2347 IShellItem_Release(shellitem);
2350 /* if a parent pidl and shellfolder are specified, the shellfolder is ignored */
2351 ret = pSHCreateShellItem(pidl_cwd, desktopfolder, pidl_testfile, &shellitem);
2352 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2353 if (SUCCEEDED(ret))
2355 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2356 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2357 if (SUCCEEDED(ret))
2359 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2360 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2361 if (SUCCEEDED(ret))
2363 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2364 pILFree(pidl_test);
2366 IPersistIDList_Release(persistidl);
2368 IShellItem_Release(shellitem);
2371 ret = pSHCreateShellItem(NULL, desktopfolder, pidl_testfile, &shellitem);
2372 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2373 if (SUCCEEDED(ret))
2375 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2376 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2377 if (SUCCEEDED(ret))
2379 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2380 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2381 if (SUCCEEDED(ret))
2383 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2384 pILFree(pidl_test);
2386 IPersistIDList_Release(persistidl);
2389 IShellItem_Release(shellitem);
2392 ret = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
2393 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2394 if (SUCCEEDED(ret))
2396 ret = IShellItem_GetParent(shellitem, &shellitem2);
2397 ok(FAILED(ret), "Got 0x%08x\n", ret);
2398 if(SUCCEEDED(ret)) IShellItem_Release(shellitem2);
2399 IShellItem_Release(shellitem);
2402 /* SHCreateItemFromParsingName */
2403 if(pSHCreateItemFromParsingName)
2405 if(0)
2407 /* Crashes under windows 7 */
2408 pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, NULL);
2411 shellitem = (void*)0xdeadbeef;
2412 ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, (void**)&shellitem);
2413 ok(ret == E_INVALIDARG, "SHCreateItemFromParsingName returned %x\n", ret);
2414 ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2416 ret = pSHCreateItemFromParsingName(testfileW, NULL, &IID_IShellItem, (void**)&shellitem);
2417 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
2418 "SHCreateItemFromParsingName returned %x\n", ret);
2419 if(SUCCEEDED(ret)) IShellItem_Release(shellitem);
2421 lstrcpyW(fnbufW, curdirW);
2422 myPathAddBackslashW(fnbufW);
2423 lstrcatW(fnbufW, testfileW);
2425 ret = pSHCreateItemFromParsingName(fnbufW, NULL, &IID_IShellItem, (void**)&shellitem);
2426 ok(ret == S_OK, "SHCreateItemFromParsingName returned %x\n", ret);
2427 if(SUCCEEDED(ret))
2429 LPWSTR tmp_fname;
2430 ret = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &tmp_fname);
2431 ok(ret == S_OK, "GetDisplayName returned %x\n", ret);
2432 if(SUCCEEDED(ret))
2434 ok(!lstrcmpW(fnbufW, tmp_fname), "strings not equal\n");
2435 CoTaskMemFree(tmp_fname);
2437 IShellItem_Release(shellitem);
2440 else
2441 win_skip("No SHCreateItemFromParsingName\n");
2444 /* SHCreateItemFromIDList */
2445 if(pSHCreateItemFromIDList)
2447 if(0)
2449 /* Crashes under win7 */
2450 pSHCreateItemFromIDList(NULL, &IID_IShellItem, NULL);
2453 ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, (void**)&shellitem);
2454 ok(ret == E_INVALIDARG, "SHCreateItemFromIDList returned %x\n", ret);
2456 ret = pSHCreateItemFromIDList(pidl_cwd, &IID_IShellItem, (void**)&shellitem);
2457 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2458 if (SUCCEEDED(ret))
2460 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2461 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2462 if (SUCCEEDED(ret))
2464 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2465 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2466 if (SUCCEEDED(ret))
2468 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2469 pILFree(pidl_test);
2471 IPersistIDList_Release(persistidl);
2473 IShellItem_Release(shellitem);
2476 ret = pSHCreateItemFromIDList(pidl_testfile, &IID_IShellItem, (void**)&shellitem);
2477 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2478 if (SUCCEEDED(ret))
2480 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2481 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2482 if (SUCCEEDED(ret))
2484 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2485 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2486 if (SUCCEEDED(ret))
2488 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2489 pILFree(pidl_test);
2491 IPersistIDList_Release(persistidl);
2493 IShellItem_Release(shellitem);
2496 else
2497 win_skip("No SHCreateItemFromIDList\n");
2499 DeleteFileA(".\\testfile");
2500 pILFree(pidl_abstestfile);
2501 pILFree(pidl_testfile);
2502 pILFree(pidl_desktop);
2503 pILFree(pidl_cwd);
2504 IShellFolder_Release(currentfolder);
2505 IShellFolder_Release(desktopfolder);
2508 static void test_SHGetNameFromIDList(void)
2510 IShellItem *shellitem;
2511 LPITEMIDLIST pidl;
2512 LPWSTR name_string;
2513 HRESULT hres;
2514 UINT i;
2515 static const DWORD flags[] = {
2516 SIGDN_NORMALDISPLAY, SIGDN_PARENTRELATIVEPARSING,
2517 SIGDN_DESKTOPABSOLUTEPARSING,SIGDN_PARENTRELATIVEEDITING,
2518 SIGDN_DESKTOPABSOLUTEEDITING, /*SIGDN_FILESYSPATH, SIGDN_URL, */
2519 SIGDN_PARENTRELATIVEFORADDRESSBAR,SIGDN_PARENTRELATIVE, -1234};
2521 if(!pSHGetNameFromIDList)
2523 win_skip("SHGetNameFromIDList missing.\n");
2524 return;
2527 /* These should be available on any platform that passed the above test. */
2528 ok(pSHCreateShellItem != NULL, "SHCreateShellItem missing.\n");
2529 ok(pSHBindToParent != NULL, "SHBindToParent missing.\n");
2530 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
2531 ok(pStrRetToBufW != NULL, "StrRetToBufW missing.\n");
2533 if(0)
2535 /* Crashes under win7 */
2536 pSHGetNameFromIDList(NULL, 0, NULL);
2539 hres = pSHGetNameFromIDList(NULL, 0, &name_string);
2540 ok(hres == E_INVALIDARG, "Got 0x%08x\n", hres);
2542 /* Test the desktop */
2543 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
2544 ok(hres == S_OK, "Got 0x%08x\n", hres);
2545 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2546 ok(hres == S_OK, "Got 0x%08x\n", hres);
2547 if(SUCCEEDED(hres))
2549 WCHAR *nameSI, *nameSH;
2550 WCHAR buf[MAX_PATH];
2551 HRESULT hrSI, hrSH, hrSF;
2552 STRRET strret;
2553 IShellFolder *psf;
2554 BOOL res;
2556 SHGetDesktopFolder(&psf);
2557 for(i = 0; flags[i] != -1234; i++)
2559 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2560 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2561 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2562 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2563 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2564 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2566 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2567 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2569 if(SUCCEEDED(hrSF))
2571 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2572 if(SUCCEEDED(hrSI))
2573 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2574 if(SUCCEEDED(hrSF))
2575 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2577 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2578 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2580 IShellFolder_Release(psf);
2582 if(pSHGetPathFromIDListW){
2583 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2584 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2585 res = pSHGetPathFromIDListW(pidl, buf);
2586 ok(res == TRUE, "Got %d\n", res);
2587 if(SUCCEEDED(hrSI) && res)
2588 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2589 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2590 }else
2591 win_skip("pSHGetPathFromIDListW not available\n");
2593 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2594 todo_wine ok(hres == S_OK, "Got 0x%08x\n", hres);
2595 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2597 IShellItem_Release(shellitem);
2599 pILFree(pidl);
2601 /* Test the control panel */
2602 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_CONTROLS, &pidl);
2603 ok(hres == S_OK, "Got 0x%08x\n", hres);
2604 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2605 ok(hres == S_OK, "Got 0x%08x\n", hres);
2606 if(SUCCEEDED(hres))
2608 WCHAR *nameSI, *nameSH;
2609 WCHAR buf[MAX_PATH];
2610 HRESULT hrSI, hrSH, hrSF;
2611 STRRET strret;
2612 IShellFolder *psf;
2613 BOOL res;
2615 SHGetDesktopFolder(&psf);
2616 for(i = 0; flags[i] != -1234; i++)
2618 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2619 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2620 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2621 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2622 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2623 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2625 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2626 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2628 if(SUCCEEDED(hrSF))
2630 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2631 if(SUCCEEDED(hrSI))
2632 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2633 if(SUCCEEDED(hrSF))
2634 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2636 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2637 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2639 IShellFolder_Release(psf);
2641 if(pSHGetPathFromIDListW){
2642 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2643 ok(hrSI == E_INVALIDARG, "Got 0x%08x\n", hrSI);
2644 res = pSHGetPathFromIDListW(pidl, buf);
2645 ok(res == FALSE, "Got %d\n", res);
2646 if(SUCCEEDED(hrSI) && res)
2647 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2648 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2649 }else
2650 win_skip("pSHGetPathFromIDListW not available\n");
2652 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2653 todo_wine ok(hres == E_NOTIMPL /* Win7 */ || hres == S_OK /* Vista */,
2654 "Got 0x%08x\n", hres);
2655 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2657 IShellItem_Release(shellitem);
2659 pILFree(pidl);
2662 static void test_SHGetItemFromDataObject(void)
2664 IShellFolder *psfdesktop;
2665 IShellItem *psi;
2666 IShellView *psv;
2667 HRESULT hres;
2669 if(!pSHGetItemFromDataObject)
2671 win_skip("No SHGetItemFromDataObject.\n");
2672 return;
2675 if(0)
2677 /* Crashes under win7 */
2678 pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, NULL);
2681 hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, (void**)&psv);
2682 ok(hres == E_INVALIDARG, "got 0x%08x\n", hres);
2684 SHGetDesktopFolder(&psfdesktop);
2686 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
2687 ok(hres == S_OK, "got 0x%08x\n", hres);
2688 if(SUCCEEDED(hres))
2690 IEnumIDList *peidl;
2691 IDataObject *pdo;
2692 SHCONTF enum_flags;
2694 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
2695 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
2696 ok(hres == S_OK, "got 0x%08x\n", hres);
2697 if(SUCCEEDED(hres))
2699 LPITEMIDLIST apidl[5];
2700 UINT count = 0, i;
2702 for(count = 0; count < 5; count++)
2703 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
2704 break;
2706 if(count)
2708 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
2709 &IID_IDataObject, NULL, (void**)&pdo);
2710 ok(hres == S_OK, "got 0x%08x\n", hres);
2711 if(SUCCEEDED(hres))
2713 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2714 ok(hres == S_OK, "got 0x%08x\n", hres);
2715 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2716 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2717 ok(hres == S_OK, "got 0x%08x\n", hres);
2718 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2719 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2720 ok(hres == S_OK, "got 0x%08x\n", hres);
2721 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2722 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2723 ok(hres == S_OK, "got 0x%08x\n", hres);
2724 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2725 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2726 ok(hres == S_OK, "got 0x%08x\n", hres);
2727 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2729 IDataObject_Release(pdo);
2732 else
2733 skip("No file(s) found - skipping single-file test.\n");
2735 if(count > 1)
2737 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
2738 &IID_IDataObject, NULL, (void**)&pdo);
2739 ok(hres == S_OK, "got 0x%08x\n", hres);
2740 if(SUCCEEDED(hres))
2742 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2743 ok(hres == S_OK, "got 0x%08x\n", hres);
2744 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2745 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2746 ok(hres == S_OK, "got 0x%08x\n", hres);
2747 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2748 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2749 ok(hres == S_OK, "got 0x%08x\n", hres);
2750 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2751 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2752 ok(hres == S_OK, "got 0x%08x\n", hres);
2753 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2754 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2755 ok(hres == E_FAIL, "got 0x%08x\n", hres);
2756 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2757 IDataObject_Release(pdo);
2760 else
2761 skip("zero or one file found - skipping multi-file test.\n");
2763 for(i = 0; i < count; i++)
2764 pILFree(apidl[i]);
2766 IEnumIDList_Release(peidl);
2769 IShellView_Release(psv);
2772 IShellFolder_Release(psfdesktop);
2775 static void test_ShellItemCompare(void)
2777 IShellItem *psi[9]; /* a\a, a\b, a\c, b\a, .. */
2778 IShellItem *psi_a = NULL, *psi_b = NULL, *psi_c = NULL;
2779 IShellFolder *psf_desktop, *psf_current;
2780 LPITEMIDLIST pidl_cwd;
2781 WCHAR curdirW[MAX_PATH];
2782 BOOL failed;
2783 HRESULT hr;
2784 static const WCHAR filesW[][9] = {
2785 {'a','\\','a',0}, {'a','\\','b',0}, {'a','\\','c',0},
2786 {'b','\\','a',0}, {'b','\\','b',0}, {'b','\\','c',0},
2787 {'c','\\','a',0}, {'c','\\','b',0}, {'c','\\','c',0} };
2788 int order;
2789 UINT i;
2791 if(!pSHCreateShellItem)
2793 win_skip("SHCreateShellItem missing.\n");
2794 return;
2797 GetCurrentDirectoryW(MAX_PATH, curdirW);
2798 if (!curdirW[0])
2800 skip("Failed to get current directory, skipping.\n");
2801 return;
2804 CreateDirectoryA(".\\a", NULL);
2805 CreateDirectoryA(".\\b", NULL);
2806 CreateDirectoryA(".\\c", NULL);
2807 CreateTestFile(".\\a\\a");
2808 CreateTestFile(".\\a\\b");
2809 CreateTestFile(".\\a\\c");
2810 CreateTestFile(".\\b\\a");
2811 CreateTestFile(".\\b\\b");
2812 CreateTestFile(".\\b\\c");
2813 CreateTestFile(".\\c\\a");
2814 CreateTestFile(".\\c\\b");
2815 CreateTestFile(".\\c\\c");
2817 SHGetDesktopFolder(&psf_desktop);
2818 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2819 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2820 hr = IShellFolder_BindToObject(psf_desktop, pidl_cwd, NULL, &IID_IShellFolder, (void**)&psf_current);
2821 ok(SUCCEEDED(hr), "BindToObject returned %x\n", hr);
2822 IShellFolder_Release(psf_desktop);
2823 ILFree(pidl_cwd);
2825 /* Generate ShellItems for the files */
2826 memset(&psi, 0, sizeof(psi));
2827 failed = FALSE;
2828 for(i = 0; i < 9; i++)
2830 LPITEMIDLIST pidl_testfile = NULL;
2832 hr = IShellFolder_ParseDisplayName(psf_current, NULL, NULL, (LPWSTR)filesW[i],
2833 NULL, &pidl_testfile, NULL);
2834 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2835 if(SUCCEEDED(hr))
2837 hr = pSHCreateShellItem(NULL, NULL, pidl_testfile, &psi[i]);
2838 ok(hr == S_OK, "Got 0x%08x\n", hr);
2839 pILFree(pidl_testfile);
2841 if(FAILED(hr)) failed = TRUE;
2843 if(failed)
2845 skip("Failed to create all shellitems.\n");
2846 goto cleanup;
2849 /* Generate ShellItems for the folders */
2850 hr = IShellItem_GetParent(psi[0], &psi_a);
2851 ok(hr == S_OK, "Got 0x%08x\n", hr);
2852 if(FAILED(hr)) failed = TRUE;
2853 hr = IShellItem_GetParent(psi[3], &psi_b);
2854 ok(hr == S_OK, "Got 0x%08x\n", hr);
2855 if(FAILED(hr)) failed = TRUE;
2856 hr = IShellItem_GetParent(psi[6], &psi_c);
2857 ok(hr == S_OK, "Got 0x%08x\n", hr);
2858 if(FAILED(hr)) failed = TRUE;
2860 if(failed)
2862 skip("Failed to create shellitems.\n");
2863 goto cleanup;
2866 if(0)
2868 /* Crashes on native (win7, winxp) */
2869 IShellItem_Compare(psi_a, NULL, 0, NULL);
2870 IShellItem_Compare(psi_a, psi_b, 0, NULL);
2871 IShellItem_Compare(psi_a, NULL, 0, &order);
2874 /* Basics */
2875 for(i = 0; i < 9; i++)
2877 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_DISPLAY, &order);
2878 ok(hr == S_OK, "Got 0x%08x\n", hr);
2879 ok(order == 0, "Got order %d\n", order);
2880 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_CANONICAL, &order);
2881 ok(hr == S_OK, "Got 0x%08x\n", hr);
2882 ok(order == 0, "Got order %d\n", order);
2883 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_ALLFIELDS, &order);
2884 ok(hr == S_OK, "Got 0x%08x\n", hr);
2885 ok(order == 0, "Got order %d\n", order);
2888 /* Order */
2889 /* a\b:a\a , a\b:a\c, a\b:a\b */
2890 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_DISPLAY, &order);
2891 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2892 ok(order == 1, "Got order %d\n", order);
2893 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_DISPLAY, &order);
2894 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2895 ok(order == -1, "Got order %d\n", order);
2896 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_DISPLAY, &order);
2897 ok(hr == S_OK, "Got 0x%08x\n", hr);
2898 ok(order == 0, "Got order %d\n", order);
2900 /* b\b:a\b, b\b:c\b, b\b:c\b */
2901 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_DISPLAY, &order);
2902 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2903 ok(order == 1, "Got order %d\n", order);
2904 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_DISPLAY, &order);
2905 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2906 ok(order == -1, "Got order %d\n", order);
2907 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_DISPLAY, &order);
2908 ok(hr == S_OK, "Got 0x%08x\n", hr);
2909 ok(order == 0, "Got order %d\n", order);
2911 /* b:a\a, b:a\c, b:a\b */
2912 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_DISPLAY, &order);
2913 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2914 todo_wine ok(order == 1, "Got order %d\n", order);
2915 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_DISPLAY, &order);
2916 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2917 todo_wine ok(order == 1, "Got order %d\n", order);
2918 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_DISPLAY, &order);
2919 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2920 todo_wine ok(order == 1, "Got order %d\n", order);
2922 /* b:c\a, b:c\c, b:c\b */
2923 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_DISPLAY, &order);
2924 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2925 ok(order == -1, "Got order %d\n", order);
2926 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_DISPLAY, &order);
2927 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2928 ok(order == -1, "Got order %d\n", order);
2929 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_DISPLAY, &order);
2930 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2931 ok(order == -1, "Got order %d\n", order);
2933 /* a\b:a\a , a\b:a\c, a\b:a\b */
2934 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_CANONICAL, &order);
2935 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2936 ok(order == 1, "Got order %d\n", order);
2937 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_CANONICAL, &order);
2938 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2939 ok(order == -1, "Got order %d\n", order);
2940 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_CANONICAL, &order);
2941 ok(hr == S_OK, "Got 0x%08x\n", hr);
2942 ok(order == 0, "Got order %d\n", order);
2944 /* b\b:a\b, b\b:c\b, b\b:c\b */
2945 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_CANONICAL, &order);
2946 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2947 ok(order == 1, "Got order %d\n", order);
2948 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_CANONICAL, &order);
2949 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2950 ok(order == -1, "Got order %d\n", order);
2951 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_CANONICAL, &order);
2952 ok(hr == S_OK, "Got 0x%08x\n", hr);
2953 ok(order == 0, "Got order %d\n", order);
2955 /* b:a\a, b:a\c, b:a\b */
2956 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_CANONICAL, &order);
2957 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2958 todo_wine ok(order == 1, "Got order %d\n", order);
2959 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_CANONICAL, &order);
2960 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2961 todo_wine ok(order == 1, "Got order %d\n", order);
2962 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_CANONICAL, &order);
2963 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2964 todo_wine ok(order == 1, "Got order %d\n", order);
2966 /* b:c\a, b:c\c, b:c\b */
2967 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_CANONICAL, &order);
2968 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2969 ok(order == -1, "Got order %d\n", order);
2970 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_CANONICAL, &order);
2971 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2972 ok(order == -1, "Got order %d\n", order);
2973 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_CANONICAL, &order);
2974 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2975 ok(order == -1, "Got order %d\n", order);
2977 cleanup:
2978 IShellFolder_Release(psf_current);
2980 DeleteFileA(".\\a\\a");
2981 DeleteFileA(".\\a\\b");
2982 DeleteFileA(".\\a\\c");
2983 DeleteFileA(".\\b\\a");
2984 DeleteFileA(".\\b\\b");
2985 DeleteFileA(".\\b\\c");
2986 DeleteFileA(".\\c\\a");
2987 DeleteFileA(".\\c\\b");
2988 DeleteFileA(".\\c\\c");
2989 RemoveDirectoryA(".\\a");
2990 RemoveDirectoryA(".\\b");
2991 RemoveDirectoryA(".\\c");
2993 if(psi_a) IShellItem_Release(psi_a);
2994 if(psi_b) IShellItem_Release(psi_b);
2995 if(psi_c) IShellItem_Release(psi_c);
2997 for(i = 0; i < 9; i++)
2998 if(psi[i]) IShellItem_Release(psi[i]);
3001 /**************************************************************/
3002 /* IUnknown implementation for counting QueryInterface calls. */
3003 typedef struct {
3004 IUnknown IUnknown_iface;
3005 struct if_count {
3006 REFIID id;
3007 LONG count;
3008 } *ifaces;
3009 LONG unknown;
3010 } IUnknownImpl;
3012 static inline IUnknownImpl *impl_from_IUnknown(IUnknown *iface)
3014 return CONTAINING_RECORD(iface, IUnknownImpl, IUnknown_iface);
3017 static HRESULT WINAPI unk_fnQueryInterface(IUnknown *iunk, REFIID riid, void** punk)
3019 IUnknownImpl *This = impl_from_IUnknown(iunk);
3020 UINT i;
3021 BOOL found = FALSE;
3022 for(i = 0; This->ifaces[i].id != NULL; i++)
3024 if(IsEqualIID(This->ifaces[i].id, riid))
3026 This->ifaces[i].count++;
3027 found = TRUE;
3028 break;
3031 if(!found)
3032 This->unknown++;
3033 return E_NOINTERFACE;
3036 static ULONG WINAPI unk_fnAddRef(IUnknown *iunk)
3038 return 2;
3041 static ULONG WINAPI unk_fnRelease(IUnknown *iunk)
3043 return 1;
3046 static const IUnknownVtbl vt_IUnknown = {
3047 unk_fnQueryInterface,
3048 unk_fnAddRef,
3049 unk_fnRelease
3052 static void test_SHGetIDListFromObject(void)
3054 IUnknownImpl *punkimpl;
3055 IShellFolder *psfdesktop;
3056 IShellView *psv;
3057 LPITEMIDLIST pidl, pidl_desktop;
3058 HRESULT hres;
3059 UINT i;
3060 struct if_count ifaces[] =
3061 { {&IID_IPersistIDList, 0},
3062 {&IID_IPersistFolder2, 0},
3063 {&IID_IDataObject, 0},
3064 {&IID_IParentAndItem, 0},
3065 {&IID_IFolderView, 0},
3066 {NULL, 0} };
3068 if(!pSHGetIDListFromObject)
3070 win_skip("SHGetIDListFromObject missing.\n");
3071 return;
3074 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
3076 if(0)
3078 /* Crashes native */
3079 pSHGetIDListFromObject(NULL, NULL);
3080 pSHGetIDListFromObject((void*)0xDEADBEEF, NULL);
3083 hres = pSHGetIDListFromObject(NULL, &pidl);
3084 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3086 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
3087 punkimpl->IUnknown_iface.lpVtbl = &vt_IUnknown;
3088 punkimpl->ifaces = ifaces;
3089 punkimpl->unknown = 0;
3091 hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
3092 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3093 ok(ifaces[0].count, "interface not requested.\n");
3094 ok(ifaces[1].count, "interface not requested.\n");
3095 ok(ifaces[2].count, "interface not requested.\n");
3096 todo_wine
3097 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3098 "interface not requested.\n");
3099 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3100 "interface not requested.\n");
3102 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3103 HeapFree(GetProcessHeap(), 0, punkimpl);
3105 pidl_desktop = NULL;
3106 pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3107 ok(pidl_desktop != NULL, "Failed to get desktop pidl.\n");
3109 SHGetDesktopFolder(&psfdesktop);
3111 /* Test IShellItem */
3112 if(pSHCreateShellItem)
3114 IShellItem *shellitem;
3115 hres = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
3116 ok(hres == S_OK, "got 0x%08x\n", hres);
3117 if(SUCCEEDED(hres))
3119 hres = pSHGetIDListFromObject((IUnknown*)shellitem, &pidl);
3120 ok(hres == S_OK, "got 0x%08x\n", hres);
3121 if(SUCCEEDED(hres))
3123 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3124 pILFree(pidl);
3126 IShellItem_Release(shellitem);
3129 else
3130 skip("no SHCreateShellItem.\n");
3132 /* Test IShellFolder */
3133 hres = pSHGetIDListFromObject((IUnknown*)psfdesktop, &pidl);
3134 ok(hres == S_OK, "got 0x%08x\n", hres);
3135 if(SUCCEEDED(hres))
3137 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3138 pILFree(pidl);
3141 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
3142 ok(hres == S_OK, "got 0x%08x\n", hres);
3143 if(SUCCEEDED(hres))
3145 IEnumIDList *peidl;
3146 IDataObject *pdo;
3147 SHCONTF enum_flags;
3149 /* Test IFolderView */
3150 hres = pSHGetIDListFromObject((IUnknown*)psv, &pidl);
3151 ok(hres == S_OK, "got 0x%08x\n", hres);
3152 if(SUCCEEDED(hres))
3154 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3155 pILFree(pidl);
3158 /* Test IDataObject */
3159 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3160 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
3161 ok(hres == S_OK, "got 0x%08x\n", hres);
3162 if(SUCCEEDED(hres))
3164 LPITEMIDLIST apidl[5];
3165 UINT count = 0;
3166 for(count = 0; count < 5; count++)
3167 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3168 break;
3170 if(count)
3172 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
3173 &IID_IDataObject, NULL, (void**)&pdo);
3174 ok(hres == S_OK, "got 0x%08x\n", hres);
3175 if(SUCCEEDED(hres))
3177 pidl = (void*)0xDEADBEEF;
3178 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3179 ok(hres == S_OK, "got 0x%08x\n", hres);
3180 ok(pidl != NULL, "pidl is NULL.\n");
3181 ok(ILIsEqual(pidl, apidl[0]), "pidl not equal.\n");
3182 pILFree(pidl);
3184 IDataObject_Release(pdo);
3187 else
3188 skip("No files found - skipping single-file test.\n");
3190 if(count > 1)
3192 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
3193 &IID_IDataObject, NULL, (void**)&pdo);
3194 ok(hres == S_OK, "got 0x%08x\n", hres);
3195 if(SUCCEEDED(hres))
3197 pidl = (void*)0xDEADBEEF;
3198 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3199 ok(hres == E_NOINTERFACE || hres == E_FAIL /*Vista*/,
3200 "got 0x%08x\n", hres);
3201 ok(pidl == NULL, "pidl is not NULL.\n");
3203 IDataObject_Release(pdo);
3206 else
3207 skip("zero or one file found - skipping multi-file test.\n");
3209 for(i = 0; i < count; i++)
3210 pILFree(apidl[i]);
3212 IEnumIDList_Release(peidl);
3215 IShellView_Release(psv);
3218 IShellFolder_Release(psfdesktop);
3219 pILFree(pidl_desktop);
3222 static void test_SHGetItemFromObject(void)
3224 IUnknownImpl *punkimpl;
3225 IShellFolder *psfdesktop;
3226 LPITEMIDLIST pidl;
3227 IShellItem *psi;
3228 IUnknown *punk;
3229 HRESULT hres;
3230 struct if_count ifaces[] =
3231 { {&IID_IPersistIDList, 0},
3232 {&IID_IPersistFolder2, 0},
3233 {&IID_IDataObject, 0},
3234 {&IID_IParentAndItem, 0},
3235 {&IID_IFolderView, 0},
3236 {NULL, 0} };
3238 if(!pSHGetItemFromObject)
3240 skip("No SHGetItemFromObject.\n");
3241 return;
3244 SHGetDesktopFolder(&psfdesktop);
3246 if(0)
3248 /* Crashes with Windows 7 */
3249 pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IUnknown, NULL);
3250 pSHGetItemFromObject(NULL, &IID_IUnknown, NULL);
3251 pSHGetItemFromObject((IUnknown*)psfdesktop, NULL, (void**)&punk);
3254 hres = pSHGetItemFromObject(NULL, &IID_IUnknown, (void**)&punk);
3255 ok(hres == E_NOINTERFACE, "Got 0x%08x\n", hres);
3257 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
3258 punkimpl->IUnknown_iface.lpVtbl = &vt_IUnknown;
3259 punkimpl->ifaces = ifaces;
3260 punkimpl->unknown = 0;
3262 /* The same as SHGetIDListFromObject */
3263 hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
3264 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3265 ok(ifaces[0].count, "interface not requested.\n");
3266 ok(ifaces[1].count, "interface not requested.\n");
3267 ok(ifaces[2].count, "interface not requested.\n");
3268 todo_wine
3269 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3270 "interface not requested.\n");
3271 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3272 "interface not requested.\n");
3274 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3275 HeapFree(GetProcessHeap(), 0, punkimpl);
3277 /* Test IShellItem */
3278 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IShellItem, (void**)&psi);
3279 ok(hres == S_OK, "Got 0x%08x\n", hres);
3280 if(SUCCEEDED(hres))
3282 IShellItem *psi2;
3283 hres = pSHGetItemFromObject((IUnknown*)psi, &IID_IShellItem, (void**)&psi2);
3284 ok(hres == S_OK, "Got 0x%08x\n", hres);
3285 if(SUCCEEDED(hres))
3287 todo_wine
3288 ok(psi == psi2, "Different instances (%p != %p).\n", psi, psi2);
3289 IShellItem_Release(psi2);
3291 IShellItem_Release(psi);
3294 IShellFolder_Release(psfdesktop);
3297 static void test_SHCreateShellItemArray(void)
3299 IShellFolder *pdesktopsf, *psf;
3300 IShellItemArray *psia;
3301 IEnumIDList *peidl;
3302 HRESULT hr;
3303 WCHAR cTestDirW[MAX_PATH];
3304 LPITEMIDLIST pidl_testdir, pidl;
3305 static const WCHAR testdirW[] = {'t','e','s','t','d','i','r',0};
3307 if(!pSHCreateShellItemArray) {
3308 skip("No pSHCreateShellItemArray!\n");
3309 return;
3312 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
3314 if(0)
3316 /* Crashes under native */
3317 pSHCreateShellItemArray(NULL, NULL, 0, NULL, NULL);
3318 pSHCreateShellItemArray(NULL, NULL, 1, NULL, NULL);
3319 pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, NULL);
3320 pSHCreateShellItemArray(pidl, NULL, 0, NULL, NULL);
3323 hr = pSHCreateShellItemArray(NULL, NULL, 0, NULL, &psia);
3324 ok(hr == E_POINTER, "got 0x%08x\n", hr);
3326 SHGetDesktopFolder(&pdesktopsf);
3327 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, &psia);
3328 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3330 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 1, NULL, &psia);
3331 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3333 pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
3334 hr = pSHCreateShellItemArray(pidl, NULL, 0, NULL, &psia);
3335 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3336 pILFree(pidl);
3338 GetCurrentDirectoryW(MAX_PATH, cTestDirW);
3339 myPathAddBackslashW(cTestDirW);
3340 lstrcatW(cTestDirW, testdirW);
3342 CreateFilesFolders();
3344 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, cTestDirW, NULL, &pidl_testdir, 0);
3345 ok(hr == S_OK, "got 0x%08x\n", hr);
3346 if(SUCCEEDED(hr))
3348 hr = IShellFolder_BindToObject(pdesktopsf, pidl_testdir, NULL, (REFIID)&IID_IShellFolder,
3349 (void**)&psf);
3350 ok(hr == S_OK, "Got 0x%08x\n", hr);
3352 IShellFolder_Release(pdesktopsf);
3354 if(FAILED(hr))
3356 skip("Failed to set up environment for SHCreateShellItemArray tests.\n");
3357 pILFree(pidl_testdir);
3358 Cleanup();
3359 return;
3362 hr = IShellFolder_EnumObjects(psf, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &peidl);
3363 ok(hr == S_OK, "Got %08x\n", hr);
3364 if(SUCCEEDED(hr))
3366 LPITEMIDLIST apidl[5];
3367 UINT done, numitems, i;
3369 for(done = 0; done < 5; done++)
3370 if(IEnumIDList_Next(peidl, 1, &apidl[done], NULL) != S_OK)
3371 break;
3372 ok(done == 5, "Got %d pidls\n", done);
3373 IEnumIDList_Release(peidl);
3375 /* Create a ShellItemArray */
3376 hr = pSHCreateShellItemArray(NULL, psf, done, (LPCITEMIDLIST*)apidl, &psia);
3377 ok(hr == S_OK, "Got 0x%08x\n", hr);
3378 if(SUCCEEDED(hr))
3380 IShellItem *psi;
3382 if(0)
3384 /* Crashes in Windows 7 */
3385 IShellItemArray_GetCount(psia, NULL);
3388 IShellItemArray_GetCount(psia, &numitems);
3389 ok(numitems == done, "Got %d, expected %d\n", numitems, done);
3391 hr = IShellItemArray_GetItemAt(psia, numitems, &psi);
3392 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3394 /* Compare all the items */
3395 for(i = 0; i < numitems; i++)
3397 LPITEMIDLIST pidl_abs;
3398 pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3400 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3401 ok(hr == S_OK, "(%d) Failed with 0x%08x\n", i, hr);
3402 if(SUCCEEDED(hr))
3404 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3405 ok(hr == S_OK, "Got 0x%08x\n", hr);
3406 if(SUCCEEDED(hr))
3408 ok(ILIsEqual(pidl_abs, pidl), "Pidl not equal.\n");
3409 pILFree(pidl);
3411 IShellItem_Release(psi);
3413 pILFree(pidl_abs);
3415 for(i = 0; i < done; i++)
3416 pILFree(apidl[i]);
3417 IShellItemArray_Release(psia);
3421 /* SHCreateShellItemArrayFromShellItem */
3422 if(pSHCreateShellItemArrayFromShellItem)
3424 IShellItem *psi;
3426 if(0)
3428 /* Crashes under Windows 7 */
3429 pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, NULL);
3430 pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, (void**)&psia);
3431 pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, NULL);
3434 hr = pSHCreateItemFromIDList(pidl_testdir, &IID_IShellItem, (void**)&psi);
3435 ok(hr == S_OK, "Got 0x%08x\n", hr);
3436 if(SUCCEEDED(hr))
3438 hr = pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, (void**)&psia);
3439 ok(hr == S_OK, "Got 0x%08x\n", hr);
3440 if(SUCCEEDED(hr))
3442 IShellItem *psi2;
3443 UINT count;
3444 hr = IShellItemArray_GetCount(psia, &count);
3445 ok(hr == S_OK, "Got 0x%08x\n", hr);
3446 ok(count == 1, "Got count %d\n", count);
3447 hr = IShellItemArray_GetItemAt(psia, 0, &psi2);
3448 ok(hr == S_OK, "Got 0x%08x\n", hr);
3449 todo_wine
3450 ok(psi != psi2, "ShellItems are of the same instance.\n");
3451 if(SUCCEEDED(hr))
3453 LPITEMIDLIST pidl1, pidl2;
3454 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl1);
3455 ok(hr == S_OK, "Got 0x%08x\n", hr);
3456 ok(pidl1 != NULL, "pidl1 was null.\n");
3457 hr = pSHGetIDListFromObject((IUnknown*)psi2, &pidl2);
3458 ok(hr == S_OK, "Got 0x%08x\n", hr);
3459 ok(pidl2 != NULL, "pidl2 was null.\n");
3460 ok(ILIsEqual(pidl1, pidl2), "pidls not equal.\n");
3461 pILFree(pidl1);
3462 pILFree(pidl2);
3463 IShellItem_Release(psi2);
3465 hr = IShellItemArray_GetItemAt(psia, 1, &psi2);
3466 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3467 IShellItemArray_Release(psia);
3469 IShellItem_Release(psi);
3472 else
3473 skip("No SHCreateShellItemArrayFromShellItem.\n");
3475 if(pSHCreateShellItemArrayFromDataObject)
3477 IShellView *psv;
3479 if(0)
3481 /* Crashes under Windows 7 */
3482 pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, NULL);
3484 hr = pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, (void**)&psia);
3485 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3487 hr = IShellFolder_CreateViewObject(psf, NULL, &IID_IShellView, (void**)&psv);
3488 ok(hr == S_OK, "got 0x%08x\n", hr);
3489 if(SUCCEEDED(hr))
3491 IEnumIDList *peidl;
3492 IDataObject *pdo;
3493 SHCONTF enum_flags;
3495 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3496 hr = IShellFolder_EnumObjects(psf, NULL, enum_flags, &peidl);
3497 ok(hr == S_OK, "got 0x%08x\n", hr);
3498 if(SUCCEEDED(hr))
3500 LPITEMIDLIST apidl[5];
3501 UINT count, i;
3503 for(count = 0; count < 5; count++)
3504 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3505 break;
3506 ok(count == 5, "Got %d\n", count);
3508 if(count)
3510 hr = IShellFolder_GetUIObjectOf(psf, NULL, count, (LPCITEMIDLIST*)apidl,
3511 &IID_IDataObject, NULL, (void**)&pdo);
3512 ok(hr == S_OK, "Got 0x%08x\n", hr);
3513 if(SUCCEEDED(hr))
3515 hr = pSHCreateShellItemArrayFromDataObject(pdo, &IID_IShellItemArray,
3516 (void**)&psia);
3517 ok(hr == S_OK, "Got 0x%08x\n", hr);
3518 if(SUCCEEDED(hr))
3520 UINT count_sia, i;
3521 hr = IShellItemArray_GetCount(psia, &count_sia);
3522 ok(hr == S_OK, "Got 0x%08x\n", hr);
3523 ok(count_sia == count, "Counts differ (%d, %d)\n", count, count_sia);
3524 for(i = 0; i < count_sia; i++)
3526 LPITEMIDLIST pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3527 IShellItem *psi;
3528 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3529 ok(hr == S_OK, "Got 0x%08x\n", hr);
3530 if(SUCCEEDED(hr))
3532 LPITEMIDLIST pidl;
3533 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3534 ok(hr == S_OK, "Got 0x%08x\n", hr);
3535 ok(pidl != NULL, "pidl as NULL.\n");
3536 ok(ILIsEqual(pidl, pidl_abs), "pidls differ.\n");
3537 pILFree(pidl);
3538 IShellItem_Release(psi);
3540 pILFree(pidl_abs);
3543 IShellItemArray_Release(psia);
3546 IDataObject_Release(pdo);
3548 for(i = 0; i < count; i++)
3549 pILFree(apidl[i]);
3551 else
3552 skip("No files found - skipping test.\n");
3554 IEnumIDList_Release(peidl);
3556 IShellView_Release(psv);
3559 else
3560 skip("No SHCreateShellItemArrayFromDataObject.\n");
3562 if(pSHCreateShellItemArrayFromIDLists)
3564 WCHAR test1W[] = {'t','e','s','t','1','.','t','x','t',0};
3565 WCHAR test1pathW[MAX_PATH];
3566 LPITEMIDLIST pidltest1;
3567 LPCITEMIDLIST pidl_array[2];
3569 if(0)
3571 /* Crashes */
3572 hr = pSHCreateShellItemArrayFromIDLists(0, NULL, NULL);
3575 psia = (void*)0xdeadbeef;
3576 hr = pSHCreateShellItemArrayFromIDLists(0, NULL, &psia);
3577 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3578 ok(psia == NULL, "Got %p\n", psia);
3580 psia = (void*)0xdeadbeef;
3581 hr = pSHCreateShellItemArrayFromIDLists(0, pidl_array, &psia);
3582 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3583 ok(psia == NULL, "Got %p\n", psia);
3585 psia = (void*)0xdeadbeef;
3586 pidl_array[0] = NULL;
3587 hr = pSHCreateShellItemArrayFromIDLists(1, pidl_array, &psia);
3588 todo_wine ok(hr == E_OUTOFMEMORY, "Got 0x%08x\n", hr);
3589 ok(psia == NULL, "Got %p\n", psia);
3591 psia = (void*)0xdeadbeef;
3592 pidl_array[0] = pidl_testdir;
3593 pidl_array[1] = NULL;
3594 hr = pSHCreateShellItemArrayFromIDLists(2, pidl_array, &psia);
3595 todo_wine ok(hr == S_OK || broken(hr == E_INVALIDARG) /* Vista */, "Got 0x%08x\n", hr);
3596 todo_wine ok(psia != NULL || broken(psia == NULL) /* Vista */, "Got %p\n", psia);
3597 if(SUCCEEDED(hr))
3599 IShellItem *psi;
3600 UINT count = 0;
3602 hr = IShellItemArray_GetCount(psia, &count);
3603 ok(hr == S_OK, "Got 0x%08x\n", hr);
3604 ok(count == 2, "Got %d\n", count);
3606 hr = IShellItemArray_GetItemAt(psia, 0, &psi);
3607 ok(hr == S_OK, "Got 0x%08x\n", hr);
3608 if(SUCCEEDED(hr))
3610 LPWSTR path;
3611 hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3612 ok(hr == S_OK, "Got 0x%08x\n", hr);
3613 ok(!lstrcmpW(path, cTestDirW), "Got %s\n", wine_dbgstr_w(path));
3614 if(SUCCEEDED(hr))
3615 CoTaskMemFree(path);
3617 IShellItem_Release(psi);
3620 hr = IShellItemArray_GetItemAt(psia, 1, &psi);
3621 ok(hr == S_OK, "Got 0x%08x\n", hr);
3622 if(SUCCEEDED(hr))
3624 LPWSTR path;
3625 WCHAR desktoppath[MAX_PATH];
3626 BOOL result;
3628 result = pSHGetSpecialFolderPathW(NULL, desktoppath, CSIDL_DESKTOPDIRECTORY, FALSE);
3629 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
3631 hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3632 ok(hr == S_OK, "Got 0x%08x\n", hr);
3633 ok(!lstrcmpW(path, desktoppath), "Got %s\n", wine_dbgstr_w(path));
3634 if(SUCCEEDED(hr))
3635 CoTaskMemFree(path);
3637 IShellItem_Release(psi);
3641 IShellItemArray_Release(psia);
3645 /* Single pidl */
3646 psia = (void*)0xdeadbeef;
3647 pidl_array[0] = pidl_testdir;
3648 hr = pSHCreateShellItemArrayFromIDLists(1, pidl_array, &psia);
3649 ok(hr == S_OK, "Got 0x%08x\n", hr);
3650 if(SUCCEEDED(hr))
3652 IShellItem *psi;
3653 UINT count = 0;
3655 hr = IShellItemArray_GetCount(psia, &count);
3656 ok(hr == S_OK, "Got 0x%08x\n", hr);
3657 ok(count == 1, "Got %d\n", count);
3659 hr = IShellItemArray_GetItemAt(psia, 0, &psi);
3660 ok(hr == S_OK, "Got 0x%08x\n", hr);
3661 if(SUCCEEDED(hr))
3663 LPWSTR path;
3664 hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3665 ok(hr == S_OK, "Got 0x%08x\n", hr);
3666 ok(!lstrcmpW(path, cTestDirW), "Got %s\n", wine_dbgstr_w(path));
3667 if(SUCCEEDED(hr))
3668 CoTaskMemFree(path);
3670 IShellItem_Release(psi);
3673 IShellItemArray_Release(psia);
3677 lstrcpyW(test1pathW, cTestDirW);
3678 myPathAddBackslashW(test1pathW);
3679 lstrcatW(test1pathW, test1W);
3681 SHGetDesktopFolder(&pdesktopsf);
3683 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, test1pathW, NULL, &pidltest1, NULL);
3684 ok(hr == S_OK, "Got 0x%08x\n", hr);
3685 if(SUCCEEDED(hr))
3687 psia = (void*)0xdeadbeef;
3688 pidl_array[0] = pidl_testdir;
3689 pidl_array[1] = pidltest1;
3690 hr = pSHCreateShellItemArrayFromIDLists(2, pidl_array, &psia);
3691 ok(hr == S_OK, "Got 0x%08x\n", hr);
3692 if(SUCCEEDED(hr))
3694 IShellItem *psi;
3695 UINT count = 0;
3697 hr = IShellItemArray_GetCount(psia, &count);
3698 ok(hr == S_OK, "Got 0x%08x\n", hr);
3699 ok(count == 2, "Got %d\n", count);
3701 hr = IShellItemArray_GetItemAt(psia, 0, &psi);
3702 ok(hr == S_OK, "Got 0x%08x\n", hr);
3703 if(SUCCEEDED(hr))
3705 LPWSTR path;
3706 hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3707 ok(hr == S_OK, "Got 0x%08x\n", hr);
3708 ok(!lstrcmpW(path, cTestDirW), "Got %s\n", wine_dbgstr_w(path));
3709 if(SUCCEEDED(hr))
3710 CoTaskMemFree(path);
3712 IShellItem_Release(psi);
3715 hr = IShellItemArray_GetItemAt(psia, 1, &psi);
3716 ok(hr == S_OK, "Got 0x%08x\n", hr);
3717 if(SUCCEEDED(hr))
3719 LPWSTR path;
3720 hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3721 ok(hr == S_OK, "Got 0x%08x\n", hr);
3722 ok(!lstrcmpW(path, test1pathW), "Got %s\n", wine_dbgstr_w(path));
3723 if(SUCCEEDED(hr))
3724 CoTaskMemFree(path);
3726 IShellItem_Release(psi);
3730 IShellItemArray_Release(psia);
3733 pILFree(pidltest1);
3736 IShellFolder_Release(pdesktopsf);
3738 else
3739 skip("No SHCreateShellItemArrayFromIDLists.\n");
3741 IShellFolder_Release(psf);
3742 pILFree(pidl_testdir);
3743 Cleanup();
3746 static void test_ShellItemArrayEnumItems(void)
3748 IShellFolder *pdesktopsf, *psf;
3749 IEnumIDList *peidl;
3750 WCHAR cTestDirW[MAX_PATH];
3751 HRESULT hr;
3752 LPITEMIDLIST pidl_testdir;
3753 static const WCHAR testdirW[] = {'t','e','s','t','d','i','r',0};
3755 if(!pSHCreateShellItemArray)
3757 win_skip("No SHCreateShellItemArray, skipping test...\n");
3758 return;
3761 CreateFilesFolders();
3763 SHGetDesktopFolder(&pdesktopsf);
3765 GetCurrentDirectoryW(MAX_PATH, cTestDirW);
3766 myPathAddBackslashW(cTestDirW);
3767 lstrcatW(cTestDirW, testdirW);
3769 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, cTestDirW, NULL, &pidl_testdir, 0);
3770 ok(hr == S_OK, "got 0x%08x\n", hr);
3771 if(SUCCEEDED(hr))
3773 hr = IShellFolder_BindToObject(pdesktopsf, pidl_testdir, NULL, (REFIID)&IID_IShellFolder,
3774 (void**)&psf);
3775 ok(hr == S_OK, "Got 0x%08x\n", hr);
3776 if(SUCCEEDED(hr))
3777 pILFree(pidl_testdir);
3779 IShellFolder_Release(pdesktopsf);
3781 hr = IShellFolder_EnumObjects(psf, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &peidl);
3782 ok(hr == S_OK, "Got %08x\n", hr);
3783 if(SUCCEEDED(hr))
3785 IShellItemArray *psia;
3786 LPITEMIDLIST apidl[5];
3787 UINT done, numitems, i;
3789 for(done = 0; done < 5; done++)
3790 if(IEnumIDList_Next(peidl, 1, &apidl[done], NULL) != S_OK)
3791 break;
3792 ok(done == 5, "Got %d pidls\n", done);
3793 IEnumIDList_Release(peidl);
3795 /* Create a ShellItemArray */
3796 hr = pSHCreateShellItemArray(NULL, psf, done, (LPCITEMIDLIST*)apidl, &psia);
3797 ok(hr == S_OK, "Got 0x%08x\n", hr);
3798 if(SUCCEEDED(hr))
3800 IEnumShellItems *iesi;
3801 IShellItem *my_array[10];
3802 ULONG fetched;
3804 IShellItemArray_GetCount(psia, &numitems);
3805 ok(numitems == done, "Got %d, expected %d\n", numitems, done);
3807 iesi = NULL;
3808 hr = IShellItemArray_EnumItems(psia, &iesi);
3809 ok(hr == S_OK, "Got 0x%08x\n", hr);
3810 ok(iesi != NULL, "Got NULL\n");
3811 if(SUCCEEDED(hr))
3813 IEnumShellItems *iesi2;
3815 /* This should fail according to the documentation and Win7+ */
3816 for(i = 0; i < 10; i++) my_array[i] = (void*)0xdeadbeef;
3817 hr = IEnumShellItems_Next(iesi, 2, my_array, NULL);
3818 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* Vista */, "Got 0x%08x\n", hr);
3819 for(i = 0; i < 2; i++)
3821 ok(my_array[i] == (void*)0xdeadbeef ||
3822 broken(my_array[i] != (void*)0xdeadbeef && my_array[i] != NULL), /* Vista */
3823 "Got %p (%d)\n", my_array[i], i);
3825 if(my_array[i] != (void*)0xdeadbeef)
3826 IShellItem_Release(my_array[i]);
3828 ok(my_array[2] == (void*)0xdeadbeef, "Got %p\n", my_array[2]);
3830 IEnumShellItems_Reset(iesi);
3831 for(i = 0; i < 10; i++) my_array[i] = (void*)0xdeadbeef;
3832 hr = IEnumShellItems_Next(iesi, 1, my_array, NULL);
3833 ok(hr == S_OK, "Got 0x%08x\n", hr);
3834 ok(my_array[0] != NULL && my_array[0] != (void*)0xdeadbeef, "Got %p\n", my_array[0]);
3835 if(my_array[0] != NULL && my_array[0] != (void*)0xdeadbeef)
3836 IShellItem_Release(my_array[0]);
3837 ok(my_array[1] == (void*)0xdeadbeef, "Got %p\n", my_array[1]);
3839 IEnumShellItems_Reset(iesi);
3840 fetched = 0;
3841 for(i = 0; i < 10; i++) my_array[i] = (void*)0xdeadbeef;
3842 hr = IEnumShellItems_Next(iesi, numitems, my_array, &fetched);
3843 ok(hr == S_OK, "Got 0x%08x\n", hr);
3844 ok(fetched == numitems, "Got %d\n", fetched);
3845 for(i = 0;i < numitems; i++)
3847 ok(my_array[i] != NULL && my_array[i] != (void*)0xdeadbeef,
3848 "Got %p at %d\n", my_array[i], i);
3850 if(my_array[i] != NULL && my_array[i] != (void*)0xdeadbeef)
3851 IShellItem_Release(my_array[i]);
3853 ok(my_array[i] == (void*)0xdeadbeef, "Got %p\n", my_array[i]);
3855 /* Compare all the items */
3856 IEnumShellItems_Reset(iesi);
3857 for(i = 0; i < numitems; i++)
3859 IShellItem *psi;
3860 int order;
3862 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3863 ok(hr == S_OK, "Got 0x%08x\n", hr);
3864 hr = IEnumShellItems_Next(iesi, 1, my_array, &fetched);
3865 ok(hr == S_OK, "Got 0x%08x\n", hr);
3866 ok(fetched == 1, "Got %d\n", fetched);
3868 hr = IShellItem_Compare(psi, my_array[0], 0, &order);
3869 ok(hr == S_OK, "Got 0x%08x\n", hr);
3870 ok(order == 0, "Got %d\n", order);
3872 IShellItem_Release(psi);
3873 IShellItem_Release(my_array[0]);
3876 my_array[0] = (void*)0xdeadbeef;
3877 hr = IEnumShellItems_Next(iesi, 1, my_array, &fetched);
3878 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3879 ok(fetched == 0, "Got %d\n", fetched);
3880 ok(my_array[0] == (void*)0xdeadbeef, "Got %p\n", my_array[0]);
3882 /* Cloning not implemented anywhere */
3883 iesi2 = (void*)0xdeadbeef;
3884 hr = IEnumShellItems_Clone(iesi, &iesi2);
3885 ok(hr == E_NOTIMPL, "Got 0x%08x\n", hr);
3886 ok(iesi2 == NULL || broken(iesi2 == (void*)0xdeadbeef) /* Vista */, "Got %p\n", iesi2);
3888 IEnumShellItems_Release(iesi);
3891 IShellItemArray_Release(psia);
3894 for(i = 0; i < done; i++)
3895 pILFree(apidl[i]);
3900 static void test_ShellItemBindToHandler(void)
3902 IShellItem *psi;
3903 LPITEMIDLIST pidl_desktop;
3904 HRESULT hr;
3906 if(!pSHCreateShellItem)
3908 skip("SHCreateShellItem missing.\n");
3909 return;
3912 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3913 ok(hr == S_OK, "Got 0x%08x\n", hr);
3914 if(SUCCEEDED(hr))
3916 hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
3917 ok(hr == S_OK, "Got 0x%08x\n", hr);
3919 if(SUCCEEDED(hr))
3921 IPersistFolder2 *ppf2;
3922 IUnknown *punk;
3924 if(0)
3926 /* Crashes under Windows 7 */
3927 IShellItem_BindToHandler(psi, NULL, NULL, NULL, NULL);
3928 IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, NULL);
3930 hr = IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, (void**)&punk);
3931 ok(hr == MK_E_NOOBJECT, "Got 0x%08x\n", hr);
3933 /* BHID_SFObject */
3934 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IShellFolder, (void**)&punk);
3935 ok(hr == S_OK, "Got 0x%08x\n", hr);
3936 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3937 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IPersistFolder2, (void**)&ppf2);
3938 ok(hr == S_OK, "Got 0x%08x\n", hr);
3939 if(SUCCEEDED(hr))
3941 LPITEMIDLIST pidl_tmp;
3942 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl_tmp);
3943 ok(hr == S_OK, "Got 0x%08x\n", hr);
3944 if(SUCCEEDED(hr))
3946 ok(ILIsEqual(pidl_desktop, pidl_tmp), "Pidl not equal (%p, %p)\n", pidl_desktop, pidl_tmp);
3947 pILFree(pidl_tmp);
3949 IPersistFolder2_Release(ppf2);
3952 /* BHID_SFUIObject */
3953 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IDataObject, (void**)&punk);
3954 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3955 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3956 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IContextMenu, (void**)&punk);
3957 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3958 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3960 /* BHID_DataObject */
3961 hr = IShellItem_BindToHandler(psi, NULL, &BHID_DataObject, &IID_IDataObject, (void**)&punk);
3962 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3963 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3965 todo_wine
3967 /* BHID_SFViewObject */
3968 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellView, (void**)&punk);
3969 ok(hr == S_OK, "Got 0x%08x\n", hr);
3970 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3971 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellFolderView, (void**)&punk);
3972 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3973 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3975 /* BHID_Storage */
3976 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IStream, (void**)&punk);
3977 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3978 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3979 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IUnknown, (void**)&punk);
3980 ok(hr == S_OK, "Got 0x%08x\n", hr);
3981 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3983 /* BHID_Stream */
3984 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IStream, (void**)&punk);
3985 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3986 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3987 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IUnknown, (void**)&punk);
3988 ok(hr == S_OK, "Got 0x%08x\n", hr);
3989 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3991 /* BHID_StorageEnum */
3992 hr = IShellItem_BindToHandler(psi, NULL, &BHID_StorageEnum, &IID_IEnumShellItems, (void**)&punk);
3993 ok(hr == S_OK, "Got 0x%08x\n", hr);
3994 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3996 /* BHID_Transfer
3997 ITransferSource and ITransferDestination are accessible starting from Vista, IUnknown is
3998 supported starting from Win8. */
3999 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_ITransferSource, (void**)&punk);
4000 ok(hr == S_OK || broken(FAILED(hr)) /* pre-Vista */, "Got 0x%08x\n", hr);
4001 if(SUCCEEDED(hr))
4003 IUnknown_Release(punk);
4005 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_ITransferDestination, (void**)&punk);
4006 ok(hr == S_OK, "Got 0x%08x\n", hr);
4007 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4009 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_IUnknown, (void**)&punk);
4010 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* pre-Win8 */, "Got 0x%08x\n", hr);
4011 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4014 /* BHID_EnumItems */
4015 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumItems, &IID_IEnumShellItems, (void**)&punk);
4016 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4017 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4019 /* BHID_Filter */
4020 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Filter, &IID_IUnknown, (void**)&punk);
4021 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4022 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4024 /* BHID_LinkTargetItem */
4025 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IShellItem, (void**)&punk);
4026 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
4027 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4028 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IUnknown, (void**)&punk);
4029 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
4030 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4032 /* BHID_PropertyStore */
4033 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStore, (void**)&punk);
4034 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4035 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4036 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStoreFactory, (void**)&punk);
4037 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4038 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4040 /* BHID_ThumbnailHandler */
4041 hr = IShellItem_BindToHandler(psi, NULL, &BHID_ThumbnailHandler, &IID_IUnknown, (void**)&punk);
4042 ok(hr == E_INVALIDARG || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4043 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4045 /* BHID_AssociationArray */
4046 hr = IShellItem_BindToHandler(psi, NULL, &BHID_AssociationArray, &IID_IQueryAssociations, (void**)&punk);
4047 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4048 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4050 /* BHID_EnumAssocHandlers */
4051 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumAssocHandlers, &IID_IUnknown, (void**)&punk);
4052 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4053 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4056 IShellItem_Release(psi);
4058 else
4059 skip("Failed to create ShellItem.\n");
4061 pILFree(pidl_desktop);
4064 static void test_ShellItemGetAttributes(void)
4066 IShellItem *psi, *psi_folder1, *psi_file1;
4067 IShellFolder *pdesktopsf;
4068 LPITEMIDLIST pidl_desktop, pidl;
4069 SFGAOF sfgao;
4070 HRESULT hr;
4071 WCHAR curdirW[MAX_PATH];
4072 WCHAR buf[MAX_PATH];
4073 static const WCHAR testdir1W[] = {'t','e','s','t','d','i','r',0};
4074 static const WCHAR testfile1W[] = {'t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
4076 if(!pSHCreateShellItem)
4078 skip("SHCreateShellItem missing.\n");
4079 return;
4082 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
4083 ok(hr == S_OK, "Got 0x%08x\n", hr);
4084 if(SUCCEEDED(hr))
4086 hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
4087 ok(hr == S_OK, "Got 0x%08x\n", hr);
4088 pILFree(pidl_desktop);
4090 if(FAILED(hr))
4092 skip("Skipping tests.\n");
4093 return;
4096 if(0)
4098 /* Crashes on native (Win 7) */
4099 IShellItem_GetAttributes(psi, 0, NULL);
4102 /* Test GetAttributes on the desktop folder. */
4103 sfgao = 0xdeadbeef;
4104 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER, &sfgao);
4105 ok(hr == S_OK || broken(hr == E_FAIL) /* <Vista */, "Got 0x%08x\n", hr);
4106 ok(sfgao == SFGAO_FOLDER || broken(sfgao == 0) /* <Vista */, "Got 0x%08x\n", sfgao);
4108 IShellItem_Release(psi);
4110 CreateFilesFolders();
4112 SHGetDesktopFolder(&pdesktopsf);
4114 GetCurrentDirectoryW(MAX_PATH, curdirW);
4115 myPathAddBackslashW(curdirW);
4117 lstrcpyW(buf, curdirW);
4118 lstrcatW(buf, testdir1W);
4119 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, buf, NULL, &pidl, NULL);
4120 ok(hr == S_OK, "got 0x%08x\n", hr);
4121 hr = pSHCreateShellItem(NULL, NULL, pidl, &psi_folder1);
4122 ok(hr == S_OK, "Got 0x%08x\n", sfgao);
4123 pILFree(pidl);
4125 lstrcpyW(buf, curdirW);
4126 lstrcatW(buf, testfile1W);
4127 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, buf, NULL, &pidl, NULL);
4128 ok(hr == S_OK, "got 0x%08x\n", hr);
4129 hr = pSHCreateShellItem(NULL, NULL, pidl, &psi_file1);
4130 ok(hr == S_OK, "Got 0x%08x\n", sfgao);
4131 pILFree(pidl);
4133 IShellFolder_Release(pdesktopsf);
4135 sfgao = 0xdeadbeef;
4136 hr = IShellItem_GetAttributes(psi_folder1, 0, &sfgao);
4137 ok(hr == S_OK, "Got 0x%08x\n", hr);
4138 ok(sfgao == 0, "Got 0x%08x\n", sfgao);
4140 sfgao = 0xdeadbeef;
4141 hr = IShellItem_GetAttributes(psi_folder1, SFGAO_FOLDER, &sfgao);
4142 ok(hr == S_OK, "Got 0x%08x\n", hr);
4143 ok(sfgao == SFGAO_FOLDER, "Got 0x%08x\n", sfgao);
4145 sfgao = 0xdeadbeef;
4146 hr = IShellItem_GetAttributes(psi_file1, SFGAO_FOLDER, &sfgao);
4147 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
4148 ok(sfgao == 0, "Got 0x%08x\n", sfgao);
4150 IShellItem_Release(psi_folder1);
4151 IShellItem_Release(psi_file1);
4153 Cleanup();
4156 static void test_ShellItemArrayGetAttributes(void)
4158 IShellItemArray *psia_files, *psia_folders1, *psia_folders2, *psia_all;
4159 IShellFolder *pdesktopsf;
4160 LPCITEMIDLIST pidl_array[5];
4161 SFGAOF attr;
4162 HRESULT hr;
4163 WCHAR curdirW[MAX_PATH];
4164 WCHAR buf[MAX_PATH];
4165 UINT i;
4166 static const WCHAR testdir1W[] = {'t','e','s','t','d','i','r',0};
4167 static const WCHAR testdir2W[] = {'t','e','s','t','d','i','r','\\','t','e','s','t','d','i','r','2',0};
4168 static const WCHAR testdir3W[] = {'t','e','s','t','d','i','r','\\','t','e','s','t','d','i','r','3',0};
4169 static const WCHAR testfile1W[] = {'t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
4170 static const WCHAR testfile2W[] = {'t','e','s','t','d','i','r','\\','t','e','s','t','2','.','t','x','t',0};
4171 static const WCHAR *testfilesW[5] = { testdir1W, testdir2W, testdir3W, testfile1W, testfile2W };
4173 if(!pSHCreateShellItemArrayFromShellItem)
4175 win_skip("No SHCreateShellItemArrayFromShellItem, skipping test...\n");
4176 return;
4179 CreateFilesFolders();
4180 CreateDirectoryA(".\\testdir\\testdir3", NULL);
4182 SHGetDesktopFolder(&pdesktopsf);
4184 GetCurrentDirectoryW(MAX_PATH, curdirW);
4185 myPathAddBackslashW(curdirW);
4187 for(i = 0; i < 5; i++)
4189 lstrcpyW(buf, curdirW);
4190 lstrcatW(buf, testfilesW[i]);
4191 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, buf, NULL, (LPITEMIDLIST*)&pidl_array[i], NULL);
4192 ok(hr == S_OK, "got 0x%08x\n", hr);
4194 IShellFolder_Release(pdesktopsf);
4196 hr = pSHCreateShellItemArrayFromIDLists(2, pidl_array, &psia_folders1);
4197 ok(hr == S_OK, "got 0x%08x\n", hr);
4198 hr = pSHCreateShellItemArrayFromIDLists(2, &pidl_array[1], &psia_folders2);
4199 ok(hr == S_OK, "got 0x%08x\n", hr);
4200 hr = pSHCreateShellItemArrayFromIDLists(2, &pidl_array[3], &psia_files);
4201 ok(hr == S_OK, "got 0x%08x\n", hr);
4202 hr = pSHCreateShellItemArrayFromIDLists(4, &pidl_array[1], &psia_all); /* All except the first */
4203 ok(hr == S_OK, "got 0x%08x\n", hr);
4205 for(i = 0; i < 5; i++)
4206 pILFree((LPITEMIDLIST)pidl_array[i]);
4208 /* [testfolder/, testfolder/testfolder2] seems to break in Vista */
4209 attr = 0xdeadbeef;
4210 hr = IShellItemArray_GetAttributes(psia_folders1, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attr);
4211 ok(hr == S_OK || broken(hr == E_UNEXPECTED) /* Vista */, "Got 0x%08x\n", hr);
4212 ok(attr == SFGAO_FOLDER || broken(attr == 0) /* Vista */, "Got 0x%08x\n", attr);
4213 attr = 0xdeadbeef;
4214 hr = IShellItemArray_GetAttributes(psia_folders1, SIATTRIBFLAGS_OR, SFGAO_FOLDER, &attr);
4215 ok(hr == S_OK || broken(hr == E_UNEXPECTED) /* Vista */, "Got 0x%08x\n", hr);
4216 ok(attr == SFGAO_FOLDER || broken(attr == 0) /* Vista */, "Got 0x%08x\n", attr);
4218 /* [testfolder/testfolder2, testfolder/testfolder3] works */
4219 attr = 0xdeadbeef;
4220 hr = IShellItemArray_GetAttributes(psia_folders2, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attr);
4221 ok(hr == S_OK, "Got 0x%08x\n", hr);
4222 ok(attr == SFGAO_FOLDER, "Got 0x%08x\n", attr);
4223 attr = 0xdeadbeef;
4224 hr = IShellItemArray_GetAttributes(psia_files, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attr);
4225 ok(hr == S_FALSE || broken(hr == S_OK) /* Vista */, "Got 0x%08x\n", hr);
4226 ok(attr == 0, "Got 0x%08x\n", attr);
4227 attr = 0xdeadbeef;
4228 hr = IShellItemArray_GetAttributes(psia_all, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attr);
4229 ok(hr == S_FALSE || broken(hr == S_OK) /* Vista */, "Got 0x%08x\n", hr);
4230 ok(attr == 0, "Got 0x%08x\n", attr);
4231 attr = 0xdeadbeef;
4232 hr = IShellItemArray_GetAttributes(psia_folders2, SIATTRIBFLAGS_OR, SFGAO_FOLDER, &attr);
4233 ok(hr == S_OK, "Got 0x%08x\n", hr);
4234 ok(attr == SFGAO_FOLDER, "Got 0x%08x\n", attr);
4235 attr = 0xdeadbeef;
4236 hr = IShellItemArray_GetAttributes(psia_files, SIATTRIBFLAGS_OR, SFGAO_FOLDER, &attr);
4237 ok(hr == S_FALSE || broken(hr == S_OK) /* Vista */, "Got 0x%08x\n", hr);
4238 ok(attr == 0, "Got 0x%08x\n", attr);
4239 attr = 0xdeadbeef;
4240 hr = IShellItemArray_GetAttributes(psia_all, SIATTRIBFLAGS_OR, SFGAO_FOLDER, &attr);
4241 ok(hr == S_OK, "Got 0x%08x\n", hr);
4242 ok(attr == SFGAO_FOLDER, "Got 0x%08x\n", attr);
4244 IShellItemArray_Release(psia_folders1);
4245 IShellItemArray_Release(psia_folders2);
4246 IShellItemArray_Release(psia_files);
4247 IShellItemArray_Release(psia_all);
4249 RemoveDirectoryA(".\\testdir\\testdir3");
4250 Cleanup();
4253 static void test_SHParseDisplayName(void)
4255 LPITEMIDLIST pidl1, pidl2;
4256 IShellFolder *desktop;
4257 WCHAR dirW[MAX_PATH];
4258 WCHAR nameW[10];
4259 HRESULT hr;
4260 BOOL ret, is_wow64;
4262 if (!pSHParseDisplayName)
4264 win_skip("SHParseDisplayName isn't available\n");
4265 return;
4268 if (0)
4270 /* crashes on native */
4271 pSHParseDisplayName(NULL, NULL, NULL, 0, NULL);
4272 nameW[0] = 0;
4273 pSHParseDisplayName(nameW, NULL, NULL, 0, NULL);
4276 pidl1 = (LPITEMIDLIST)0xdeadbeef;
4277 hr = pSHParseDisplayName(NULL, NULL, &pidl1, 0, NULL);
4278 ok(broken(hr == E_OUTOFMEMORY) /* < Vista */ ||
4279 hr == E_INVALIDARG, "failed %08x\n", hr);
4280 ok(pidl1 == 0, "expected null ptr, got %p\n", pidl1);
4282 /* dummy name */
4283 nameW[0] = 0;
4284 hr = pSHParseDisplayName(nameW, NULL, &pidl1, 0, NULL);
4285 ok(hr == S_OK, "failed %08x\n", hr);
4286 hr = SHGetDesktopFolder(&desktop);
4287 ok(hr == S_OK, "failed %08x\n", hr);
4288 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, nameW, NULL, &pidl2, NULL);
4289 ok(hr == S_OK, "failed %08x\n", hr);
4290 ret = pILIsEqual(pidl1, pidl2);
4291 ok(ret == TRUE, "expected equal idls\n");
4292 pILFree(pidl1);
4293 pILFree(pidl2);
4295 /* with path */
4296 GetWindowsDirectoryW( dirW, MAX_PATH );
4298 hr = pSHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
4299 ok(hr == S_OK, "failed %08x\n", hr);
4300 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, dirW, NULL, &pidl2, NULL);
4301 ok(hr == S_OK, "failed %08x\n", hr);
4303 ret = pILIsEqual(pidl1, pidl2);
4304 ok(ret == TRUE, "expected equal idls\n");
4305 pILFree(pidl1);
4306 pILFree(pidl2);
4308 /* system32 is not redirected to syswow64 on WOW64 */
4309 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
4310 if (is_wow64 && pGetSystemWow64DirectoryW)
4312 UINT len;
4313 *dirW = 0;
4314 len = GetSystemDirectoryW(dirW, MAX_PATH);
4315 ok(len > 0, "GetSystemDirectoryW failed: %u\n", GetLastError());
4316 hr = pSHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
4317 ok(hr == S_OK, "failed %08x\n", hr);
4318 *dirW = 0;
4319 len = pGetSystemWow64DirectoryW(dirW, MAX_PATH);
4320 ok(len > 0, "GetSystemWow64DirectoryW failed: %u\n", GetLastError());
4321 hr = pSHParseDisplayName(dirW, NULL, &pidl2, 0, NULL);
4322 ok(hr == S_OK, "failed %08x\n", hr);
4323 ret = pILIsEqual(pidl1, pidl2);
4324 ok(ret == FALSE, "expected different idls\n");
4325 pILFree(pidl1);
4326 pILFree(pidl2);
4329 IShellFolder_Release(desktop);
4332 static void test_desktop_IPersist(void)
4334 IShellFolder *desktop;
4335 IPersist *persist;
4336 IPersistFolder2 *ppf2;
4337 CLSID clsid;
4338 HRESULT hr;
4340 hr = SHGetDesktopFolder(&desktop);
4341 ok(hr == S_OK, "failed %08x\n", hr);
4343 hr = IShellFolder_QueryInterface(desktop, &IID_IPersist, (void**)&persist);
4344 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* NT4, W9X */, "failed %08x\n", hr);
4346 if (hr == S_OK)
4348 if (0)
4350 /* crashes on native */
4351 IPersist_GetClassID(persist, NULL);
4353 memset(&clsid, 0, sizeof(clsid));
4354 hr = IPersist_GetClassID(persist, &clsid);
4355 ok(hr == S_OK, "failed %08x\n", hr);
4356 ok(IsEqualIID(&CLSID_ShellDesktop, &clsid), "Expected CLSID_ShellDesktop\n");
4357 IPersist_Release(persist);
4360 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder2, (void**)&ppf2);
4361 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* pre-Vista */, "failed %08x\n", hr);
4362 if(SUCCEEDED(hr))
4364 IPersistFolder *ppf;
4365 LPITEMIDLIST pidl;
4366 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder, (void**)&ppf);
4367 ok(hr == S_OK, "IID_IPersistFolder2 without IID_IPersistFolder.\n");
4368 if(SUCCEEDED(hr))
4369 IPersistFolder_Release(ppf);
4371 todo_wine {
4372 hr = IPersistFolder2_Initialize(ppf2, NULL);
4373 ok(hr == S_OK, "got %08x\n", hr);
4376 pidl = NULL;
4377 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl);
4378 ok(hr == S_OK, "got %08x\n", hr);
4379 ok(pidl != NULL, "pidl was NULL.\n");
4380 if(SUCCEEDED(hr)) pILFree(pidl);
4382 IPersistFolder2_Release(ppf2);
4385 IShellFolder_Release(desktop);
4388 static void test_GetUIObject(void)
4390 IShellFolder *psf_desktop;
4391 IContextMenu *pcm;
4392 LPITEMIDLIST pidl;
4393 HRESULT hr;
4394 WCHAR path[MAX_PATH];
4395 const WCHAR filename[] =
4396 {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
4398 if(!pSHBindToParent)
4400 win_skip("SHBindToParent missing.\n");
4401 return;
4404 GetCurrentDirectoryW(MAX_PATH, path);
4405 if (!path[0])
4407 skip("GetCurrentDirectoryW returned an empty string.\n");
4408 return;
4410 lstrcatW(path, filename);
4411 SHGetDesktopFolder(&psf_desktop);
4413 CreateFilesFolders();
4415 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, path, NULL, &pidl, 0);
4416 ok(hr == S_OK || broken(hr == E_FAIL) /* WinME */, "Got 0x%08x\n", hr);
4417 if(SUCCEEDED(hr))
4419 IShellFolder *psf;
4420 LPCITEMIDLIST pidl_child;
4421 hr = pSHBindToParent(pidl, &IID_IShellFolder, (void**)&psf, &pidl_child);
4422 ok(hr == S_OK, "Got 0x%08x\n", hr);
4423 if(SUCCEEDED(hr))
4425 hr = IShellFolder_GetUIObjectOf(psf, NULL, 1, &pidl_child, &IID_IContextMenu, NULL,
4426 (void**)&pcm);
4427 ok(hr == S_OK, "Got 0x%08x\n", hr);
4428 if(SUCCEEDED(hr))
4430 const int baseItem = 0x40;
4431 HMENU hmenu = CreatePopupMenu();
4432 INT max_id, max_id_check;
4433 UINT count, i;
4434 const int id_upper_limit = 32767;
4435 hr = IContextMenu_QueryContextMenu(pcm, hmenu, 0, baseItem, id_upper_limit, CMF_NORMAL);
4436 ok(SUCCEEDED(hr), "Got 0x%08x\n", hr);
4437 max_id = HRESULT_CODE(hr) - 1; /* returns max_id + 1 */
4438 ok(max_id <= id_upper_limit, "Got %d\n", max_id);
4439 count = GetMenuItemCount(hmenu);
4440 ok(count, "Got %d\n", count);
4442 max_id_check = 0;
4443 for(i = 0; i < count; i++)
4445 MENUITEMINFOA mii;
4446 INT res;
4447 char buf[255], buf2[255];
4448 ZeroMemory(&mii, sizeof(MENUITEMINFOA));
4449 mii.cbSize = sizeof(MENUITEMINFOA);
4450 mii.fMask = MIIM_ID | MIIM_FTYPE | MIIM_STRING;
4451 mii.dwTypeData = buf2;
4452 mii.cch = sizeof(buf2);
4454 SetLastError(0);
4455 res = GetMenuItemInfoA(hmenu, i, TRUE, &mii);
4456 ok(res, "Failed (last error: %d).\n", GetLastError());
4458 ok( (mii.wID <= id_upper_limit) || (mii.fType & MFT_SEPARATOR),
4459 "Got non-separator ID out of range: %d (type: %x)\n", mii.wID, mii.fType);
4460 if(!(mii.fType & MFT_SEPARATOR))
4462 max_id_check = (mii.wID>max_id_check)?mii.wID:max_id_check;
4463 hr = IContextMenu_GetCommandString(pcm, mii.wID - baseItem, GCS_VERBA, 0, buf, sizeof(buf));
4464 ok(SUCCEEDED(hr) || hr == E_NOTIMPL, "for id 0x%x got 0x%08x (menustr: %s)\n", mii.wID - baseItem, hr, mii.dwTypeData);
4465 if (SUCCEEDED(hr))
4466 trace("for id 0x%x got string %s (menu string: %s)\n", mii.wID - baseItem, buf, mii.dwTypeData);
4467 else if (hr == E_NOTIMPL)
4468 trace("for id 0x%x got E_NOTIMPL (menu string: %s)\n", mii.wID - baseItem, mii.dwTypeData);
4471 max_id_check -= baseItem;
4472 ok((max_id_check == max_id) ||
4473 (max_id_check == max_id-1) || /* Win 7 */
4474 (max_id_check == max_id-2), /* Win 8 */
4475 "Not equal (or near equal), got %d and %d\n", max_id_check, max_id);
4477 #define is_win2k() (pSHGetFolderPathA && !pSHGetFolderPathAndSubDirA)
4479 if(count && !is_win2k()) /* Test is interactive on w2k, so skip */
4481 CMINVOKECOMMANDINFO cmi;
4482 ZeroMemory(&cmi, sizeof(CMINVOKECOMMANDINFO));
4483 cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
4485 /* Attempt to execute a nonexistent command */
4486 cmi.lpVerb = MAKEINTRESOURCEA(9999);
4487 hr = IContextMenu_InvokeCommand(pcm, &cmi);
4488 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
4490 cmi.lpVerb = "foobar_wine_test";
4491 hr = IContextMenu_InvokeCommand(pcm, &cmi);
4492 ok( (hr == E_INVALIDARG) || (hr == E_FAIL /* Win7 */) ||
4493 (hr == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION) /* Vista */),
4494 "Got 0x%08x\n", hr);
4496 #undef is_win2k
4498 DestroyMenu(hmenu);
4499 IContextMenu_Release(pcm);
4501 IShellFolder_Release(psf);
4503 if(pILFree) pILFree(pidl);
4506 IShellFolder_Release(psf_desktop);
4507 Cleanup();
4510 #define verify_pidl(i,p) r_verify_pidl(__LINE__, i, p)
4511 static void r_verify_pidl(unsigned l, LPCITEMIDLIST pidl, const WCHAR *path)
4513 LPCITEMIDLIST child;
4514 IShellFolder *parent;
4515 STRRET filename;
4516 HRESULT hr;
4518 if(!pSHBindToParent){
4519 win_skip("SHBindToParent is not available, not performing full PIDL verification\n");
4520 if(path)
4521 ok_(__FILE__,l)(pidl != NULL, "Expected PIDL to be non-NULL\n");
4522 else
4523 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
4524 return;
4527 if(path){
4528 if(!pidl){
4529 ok_(__FILE__,l)(0, "didn't get expected path (%s), instead: NULL\n", wine_dbgstr_w(path));
4530 return;
4533 hr = pSHBindToParent(pidl, &IID_IShellFolder, (LPVOID*)&parent, &child);
4534 ok_(__FILE__,l)(hr == S_OK, "SHBindToParent failed: 0x%08x\n", hr);
4535 if(FAILED(hr))
4536 return;
4538 hr = IShellFolder_GetDisplayNameOf(parent, child, SHGDN_FORPARSING, &filename);
4539 ok_(__FILE__,l)(hr == S_OK, "GetDisplayNameOf failed: 0x%08x\n", hr);
4540 if(FAILED(hr)){
4541 IShellFolder_Release(parent);
4542 return;
4545 ok_(__FILE__,l)(filename.uType == STRRET_WSTR || filename.uType == STRRET_CSTR,
4546 "Got unexpected string type: %d\n", filename.uType);
4547 if(filename.uType == STRRET_WSTR){
4548 ok_(__FILE__,l)(lstrcmpW(path, U(filename).pOleStr) == 0,
4549 "didn't get expected path (%s), instead: %s\n",
4550 wine_dbgstr_w(path), wine_dbgstr_w(U(filename).pOleStr));
4551 SHFree(U(filename).pOleStr);
4552 }else if(filename.uType == STRRET_CSTR){
4553 ok_(__FILE__,l)(strcmp_wa(path, U(filename).cStr) == 0,
4554 "didn't get expected path (%s), instead: %s\n",
4555 wine_dbgstr_w(path), U(filename).cStr);
4558 IShellFolder_Release(parent);
4559 }else
4560 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
4563 static void test_SHSimpleIDListFromPath(void)
4565 const WCHAR adirW[] = {'C',':','\\','s','i','d','l','f','p','d','i','r',0};
4566 const CHAR adirA[] = "C:\\sidlfpdir";
4567 BOOL br, is_unicode = !(GetVersion() & 0x80000000);
4569 LPITEMIDLIST pidl = NULL;
4571 if(!pSHSimpleIDListFromPathAW){
4572 win_skip("SHSimpleIDListFromPathAW not available\n");
4573 return;
4576 br = CreateDirectoryA(adirA, NULL);
4577 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
4579 if(is_unicode)
4580 pidl = pSHSimpleIDListFromPathAW(adirW);
4581 else
4582 pidl = pSHSimpleIDListFromPathAW(adirA);
4583 verify_pidl(pidl, adirW);
4584 pILFree(pidl);
4586 br = RemoveDirectoryA(adirA);
4587 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4589 if(is_unicode)
4590 pidl = pSHSimpleIDListFromPathAW(adirW);
4591 else
4592 pidl = pSHSimpleIDListFromPathAW(adirA);
4593 verify_pidl(pidl, adirW);
4594 pILFree(pidl);
4597 /* IFileSystemBindData impl */
4598 static HRESULT WINAPI fsbd_QueryInterface(IFileSystemBindData *fsbd,
4599 REFIID riid, void **ppv)
4601 if(IsEqualIID(riid, &IID_IFileSystemBindData) ||
4602 IsEqualIID(riid, &IID_IUnknown)){
4603 *ppv = fsbd;
4604 return S_OK;
4606 return E_NOINTERFACE;
4609 static ULONG WINAPI fsbd_AddRef(IFileSystemBindData *fsbd)
4611 return 2;
4614 static ULONG WINAPI fsbd_Release(IFileSystemBindData *fsbd)
4616 return 1;
4619 static HRESULT WINAPI fsbd_SetFindData(IFileSystemBindData *fsbd,
4620 const WIN32_FIND_DATAW *pfd)
4622 ok(0, "SetFindData called\n");
4623 return E_NOTIMPL;
4626 static HRESULT WINAPI fsbd_GetFindData_nul(IFileSystemBindData *fsbd,
4627 WIN32_FIND_DATAW *pfd)
4629 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
4630 return S_OK;
4633 static HRESULT WINAPI fsbd_GetFindData_junk(IFileSystemBindData *fsbd,
4634 WIN32_FIND_DATAW *pfd)
4636 memset(pfd, 0xef, sizeof(WIN32_FIND_DATAW));
4637 return S_OK;
4640 static HRESULT WINAPI fsbd_GetFindData_invalid(IFileSystemBindData *fsbd,
4641 WIN32_FIND_DATAW *pfd)
4643 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
4644 *pfd->cFileName = 'a';
4645 *pfd->cAlternateFileName = 'a';
4646 return S_OK;
4649 static HRESULT WINAPI fsbd_GetFindData_valid(IFileSystemBindData *fsbd,
4650 WIN32_FIND_DATAW *pfd)
4652 static const WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4653 HANDLE handle = FindFirstFileW(adirW, pfd);
4654 FindClose(handle);
4655 return S_OK;
4658 static HRESULT WINAPI fsbd_GetFindData_fail(IFileSystemBindData *fsbd,
4659 WIN32_FIND_DATAW *pfd)
4661 return E_FAIL;
4664 static IFileSystemBindDataVtbl fsbdVtbl = {
4665 fsbd_QueryInterface,
4666 fsbd_AddRef,
4667 fsbd_Release,
4668 fsbd_SetFindData,
4669 NULL
4672 static IFileSystemBindData fsbd = { &fsbdVtbl };
4674 static void test_ParseDisplayNamePBC(void)
4676 WCHAR wFileSystemBindData[] =
4677 {'F','i','l','e',' ','S','y','s','t','e','m',' ','B','i','n','d',' ','D','a','t','a',0};
4678 WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4679 WCHAR afileW[] = {'C',':','\\','f','s','b','d','d','i','r','\\','f','i','l','e','.','t','x','t',0};
4680 WCHAR afile2W[] = {'C',':','\\','f','s','b','d','d','i','r','\\','s','\\','f','i','l','e','.','t','x','t',0};
4681 const HRESULT exp_err = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
4683 IShellFolder *psf;
4684 IBindCtx *pbc;
4685 HRESULT hres;
4686 ITEMIDLIST *pidl;
4688 /* Check if we support WCHAR functions */
4689 SetLastError(0xdeadbeef);
4690 lstrcmpiW(adirW, adirW);
4691 if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED){
4692 win_skip("Most W-calls are not implemented\n");
4693 return;
4696 hres = SHGetDesktopFolder(&psf);
4697 ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
4698 if(FAILED(hres)){
4699 win_skip("Failed to get IShellFolder, can't run tests\n");
4700 return;
4703 /* fails on unknown dir with no IBindCtx */
4704 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, adirW, NULL, &pidl, NULL);
4705 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4706 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4707 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, afileW, NULL, &pidl, NULL);
4708 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4709 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4710 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, afile2W, NULL, &pidl, NULL);
4711 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4712 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4714 /* fails on unknown dir with IBindCtx with no IFileSystemBindData */
4715 hres = CreateBindCtx(0, &pbc);
4716 ok(hres == S_OK, "CreateBindCtx failed: 0x%08x\n", hres);
4718 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4719 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4720 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4721 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4722 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4723 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4724 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4725 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4726 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4728 /* unknown dir with IBindCtx with IFileSystemBindData */
4729 hres = IBindCtx_RegisterObjectParam(pbc, wFileSystemBindData, (IUnknown*)&fsbd);
4730 ok(hres == S_OK, "RegisterObjectParam failed: 0x%08x\n", hres);
4732 /* return E_FAIL from GetFindData */
4733 pidl = (ITEMIDLIST*)0xdeadbeef;
4734 fsbdVtbl.GetFindData = fsbd_GetFindData_fail;
4735 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4736 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4737 "ParseDisplayName failed: 0x%08x\n", hres);
4738 if(SUCCEEDED(hres)){
4739 verify_pidl(pidl, adirW);
4740 ILFree(pidl);
4743 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4744 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4745 "ParseDisplayName failed: 0x%08x\n", hres);
4746 if(SUCCEEDED(hres)){
4747 verify_pidl(pidl, afileW);
4748 ILFree(pidl);
4751 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4752 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4753 "ParseDisplayName failed: 0x%08x\n", hres);
4754 if(SUCCEEDED(hres)){
4755 verify_pidl(pidl, afile2W);
4756 ILFree(pidl);
4759 /* set FIND_DATA struct to NULLs */
4760 pidl = (ITEMIDLIST*)0xdeadbeef;
4761 fsbdVtbl.GetFindData = fsbd_GetFindData_nul;
4762 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4763 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4764 "ParseDisplayName failed: 0x%08x\n", hres);
4765 if(SUCCEEDED(hres)){
4766 verify_pidl(pidl, adirW);
4767 ILFree(pidl);
4770 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4771 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4772 "ParseDisplayName failed: 0x%08x\n", hres);
4773 if(SUCCEEDED(hres)){
4774 verify_pidl(pidl, afileW);
4775 ILFree(pidl);
4778 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4779 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4780 "ParseDisplayName failed: 0x%08x\n", hres);
4781 if(SUCCEEDED(hres)){
4782 verify_pidl(pidl, afile2W);
4783 ILFree(pidl);
4786 /* set FIND_DATA struct to junk */
4787 pidl = (ITEMIDLIST*)0xdeadbeef;
4788 fsbdVtbl.GetFindData = fsbd_GetFindData_junk;
4789 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4790 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4791 "ParseDisplayName failed: 0x%08x\n", hres);
4792 if(SUCCEEDED(hres)){
4793 verify_pidl(pidl, adirW);
4794 ILFree(pidl);
4797 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4798 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4799 "ParseDisplayName failed: 0x%08x\n", hres);
4800 if(SUCCEEDED(hres)){
4801 verify_pidl(pidl, afileW);
4802 ILFree(pidl);
4805 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4806 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4807 "ParseDisplayName failed: 0x%08x\n", hres);
4808 if(SUCCEEDED(hres)){
4809 verify_pidl(pidl, afile2W);
4810 ILFree(pidl);
4813 /* set FIND_DATA struct to invalid data */
4814 pidl = (ITEMIDLIST*)0xdeadbeef;
4815 fsbdVtbl.GetFindData = fsbd_GetFindData_invalid;
4816 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4817 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4818 "ParseDisplayName failed: 0x%08x\n", hres);
4819 if(SUCCEEDED(hres)){
4820 verify_pidl(pidl, adirW);
4821 ILFree(pidl);
4824 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4825 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4826 "ParseDisplayName failed: 0x%08x\n", hres);
4827 if(SUCCEEDED(hres)){
4828 verify_pidl(pidl, afileW);
4829 ILFree(pidl);
4832 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4833 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4834 "ParseDisplayName failed: 0x%08x\n", hres);
4835 if(SUCCEEDED(hres)){
4836 verify_pidl(pidl, afile2W);
4837 ILFree(pidl);
4840 /* set FIND_DATA struct to valid data */
4841 pidl = (ITEMIDLIST*)0xdeadbeef;
4842 fsbdVtbl.GetFindData = fsbd_GetFindData_valid;
4843 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4844 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4845 "ParseDisplayName failed: 0x%08x\n", hres);
4846 if(SUCCEEDED(hres)){
4847 verify_pidl(pidl, adirW);
4848 ILFree(pidl);
4851 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4852 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4853 "ParseDisplayName failed: 0x%08x\n", hres);
4854 if(SUCCEEDED(hres)){
4855 verify_pidl(pidl, afileW);
4856 ILFree(pidl);
4859 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4860 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4861 "ParseDisplayName failed: 0x%08x\n", hres);
4862 if(SUCCEEDED(hres)){
4863 verify_pidl(pidl, afile2W);
4864 ILFree(pidl);
4867 IBindCtx_Release(pbc);
4868 IShellFolder_Release(psf);
4871 static const CHAR testwindow_class[] = "testwindow";
4872 #define WM_USER_NOTIFY (WM_APP+1)
4874 struct ChNotifyTest {
4875 const char id[256];
4876 const UINT notify_count;
4877 UINT missing_events;
4878 UINT signal;
4879 const char path_1[256];
4880 const char path_2[256];
4881 } chnotify_tests[] = {
4882 {"MKDIR", 1, 0, SHCNE_MKDIR, "C:\\shell32_cn_test\\test", ""},
4883 {"CREATE", 1, 0, SHCNE_CREATE, "C:\\shell32_cn_test\\test\\file.txt", ""},
4884 {"RMDIR", 1, 0, SHCNE_RMDIR, "C:\\shell32_cn_test\\test", ""},
4887 struct ChNotifyTest *exp_data;
4888 BOOL test_new_delivery_flag;
4890 static LRESULT CALLBACK testwindow_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
4892 LONG signal = (LONG)lparam;
4894 switch(msg){
4895 case WM_USER_NOTIFY:
4896 if(exp_data->missing_events > 0) {
4897 WCHAR *path1, *path2;
4898 LPITEMIDLIST *pidls = (LPITEMIDLIST*)wparam;
4899 HANDLE hLock = NULL;
4901 if(test_new_delivery_flag) {
4902 hLock = SHChangeNotification_Lock((HANDLE)wparam, lparam, &pidls, &signal);
4903 ok(hLock != NULL, "SHChangeNotification_Lock returned NULL\n");
4906 ok(exp_data->signal == signal,
4907 "%s: expected notification type %x, got: %x\n",
4908 exp_data->id, exp_data->signal, signal);
4910 trace("verifying pidls for: %s\n", exp_data->id);
4911 path1 = make_wstr(exp_data->path_1);
4912 path2 = make_wstr(exp_data->path_2);
4913 verify_pidl(pidls[0], path1);
4914 verify_pidl(pidls[1], path2);
4915 HeapFree(GetProcessHeap(), 0, path1);
4916 HeapFree(GetProcessHeap(), 0, path2);
4918 exp_data->missing_events--;
4920 if(test_new_delivery_flag)
4921 SHChangeNotification_Unlock(hLock);
4922 }else
4923 ok(0, "Didn't expect a WM_USER_NOTIFY message (event: %x)\n", signal);
4924 return 0;
4926 return DefWindowProcA(hwnd, msg, wparam, lparam);
4929 static void register_testwindow_class(void)
4931 WNDCLASSEXA cls;
4932 ATOM ret;
4934 ZeroMemory(&cls, sizeof(cls));
4935 cls.cbSize = sizeof(cls);
4936 cls.style = 0;
4937 cls.lpfnWndProc = testwindow_wndproc;
4938 cls.hInstance = GetModuleHandleA(NULL);
4939 cls.lpszClassName = testwindow_class;
4941 SetLastError(0);
4942 ret = RegisterClassExA(&cls);
4943 ok(ret != 0, "RegisterClassExA failed: %d\n", GetLastError());
4946 /* SHCNF_FLUSH doesn't seem to work as advertised for SHCNF_PATHA, so we
4947 * have to poll repeatedly for the message to appear */
4948 static void do_events(void)
4950 int c = 0;
4951 while (exp_data->missing_events && (c++ < 10)){
4952 MSG msg;
4953 while(PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)){
4954 TranslateMessage(&msg);
4955 DispatchMessageA(&msg);
4957 if(exp_data->missing_events)
4958 Sleep(500);
4960 trace("%s: took %d tries\n", exp_data->id, c);
4963 static void test_SHChangeNotify(BOOL test_new_delivery)
4965 HWND wnd;
4966 ULONG notifyID, i;
4967 HRESULT hr;
4968 BOOL br, has_unicode;
4969 SHChangeNotifyEntry entries[1];
4970 const CHAR root_dirA[] = "C:\\shell32_cn_test";
4971 const WCHAR root_dirW[] = {'C',':','\\','s','h','e','l','l','3','2','_','c','n','_','t','e','s','t',0};
4973 trace("SHChangeNotify tests (%x)\n", test_new_delivery);
4975 CreateDirectoryW(NULL, NULL);
4976 has_unicode = !(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED);
4978 test_new_delivery_flag = test_new_delivery;
4979 if(!test_new_delivery)
4980 register_testwindow_class();
4982 wnd = CreateWindowExA(0, testwindow_class, testwindow_class, 0,
4983 CW_USEDEFAULT, CW_USEDEFAULT, 130, 105,
4984 NULL, NULL, GetModuleHandleA(NULL), 0);
4985 ok(wnd != NULL, "Failed to make a window\n");
4987 br = CreateDirectoryA(root_dirA, NULL);
4988 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
4990 entries[0].pidl = NULL;
4991 if(has_unicode)
4992 hr = pSHILCreateFromPath(root_dirW, (LPITEMIDLIST*)&entries[0].pidl, 0);
4993 else
4994 hr = pSHILCreateFromPath((LPCVOID)root_dirA, (LPITEMIDLIST*)&entries[0].pidl, 0);
4995 ok(hr == S_OK, "SHILCreateFromPath failed: 0x%08x\n", hr);
4996 entries[0].fRecursive = TRUE;
4998 notifyID = SHChangeNotifyRegister(wnd, !test_new_delivery ? SHCNRF_ShellLevel : SHCNRF_ShellLevel|SHCNRF_NewDelivery,
4999 SHCNE_ALLEVENTS, WM_USER_NOTIFY, 1, entries);
5000 ok(notifyID != 0, "Failed to register a window for change notifications\n");
5002 for(i = 0; i < sizeof(chnotify_tests) / sizeof(*chnotify_tests); ++i){
5003 exp_data = chnotify_tests + i;
5005 exp_data->missing_events = exp_data->notify_count;
5006 SHChangeNotify(exp_data->signal, SHCNF_PATHA | SHCNF_FLUSH,
5007 exp_data->path_1[0] ? exp_data->path_1 : NULL,
5008 exp_data->path_2[0] ? exp_data->path_2 : NULL);
5009 do_events();
5010 ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
5012 if(has_unicode){
5013 WCHAR *path1, *path2;
5015 path1 = make_wstr(exp_data->path_1);
5016 path2 = make_wstr(exp_data->path_2);
5018 exp_data->missing_events = exp_data->notify_count;
5019 SHChangeNotify(exp_data->signal, SHCNF_PATHW | SHCNF_FLUSH, path1, path2);
5020 do_events();
5021 ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
5023 HeapFree(GetProcessHeap(), 0, path1);
5024 HeapFree(GetProcessHeap(), 0, path2);
5028 SHChangeNotifyDeregister(notifyID);
5029 DestroyWindow(wnd);
5031 ILFree((LPITEMIDLIST)entries[0].pidl);
5032 br = RemoveDirectoryA(root_dirA);
5033 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
5036 static void test_SHCreateDefaultContextMenu(void)
5038 HKEY keys[16];
5039 WCHAR path[MAX_PATH];
5040 IShellFolder *desktop,*folder;
5041 IPersistFolder2 *persist;
5042 IContextMenu *cmenu;
5043 LONG status;
5044 LPITEMIDLIST pidlFolder, pidl_child, pidl;
5045 DEFCONTEXTMENU cminfo;
5046 HRESULT hr;
5047 UINT i;
5048 const WCHAR filename[] =
5049 {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
5050 if(!pSHCreateDefaultContextMenu)
5052 win_skip("SHCreateDefaultContextMenu missing.\n");
5053 return;
5056 if(!pSHBindToParent)
5058 skip("SHBindToParent missing.\n");
5059 return;
5062 GetCurrentDirectoryW(MAX_PATH, path);
5063 if (!path[0])
5065 skip("GetCurrentDirectoryW returned an empty string.\n");
5066 return;
5068 lstrcatW(path, filename);
5069 SHGetDesktopFolder(&desktop);
5071 CreateFilesFolders();
5073 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, path, NULL, &pidl, 0);
5074 ok(hr == S_OK || broken(hr == E_FAIL) /* WinME */, "Got 0x%08x\n", hr);
5075 if(SUCCEEDED(hr))
5078 hr = pSHBindToParent(pidl, &IID_IShellFolder, (void**)&folder, (LPCITEMIDLIST*)&pidl_child);
5079 ok(hr == S_OK, "Got 0x%08x\n", hr);
5081 IShellFolder_QueryInterface(folder,&IID_IPersistFolder2,(void**)&persist);
5082 IPersistFolder2_GetCurFolder(persist,&pidlFolder);
5083 IPersistFolder2_Release(persist);
5084 if(SUCCEEDED(hr))
5087 cminfo.hwnd=NULL;
5088 cminfo.pcmcb=NULL;
5089 cminfo.psf=folder;
5090 cminfo.pidlFolder=NULL;
5091 cminfo.apidl=(LPCITEMIDLIST*)&pidl_child;
5092 cminfo.cidl=1;
5093 cminfo.aKeys=NULL;
5094 cminfo.cKeys=0;
5095 cminfo.punkAssociationInfo=NULL;
5096 hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
5097 ok(hr==S_OK,"Got 0x%08x\n", hr);
5098 IContextMenu_Release(cmenu);
5099 cminfo.pidlFolder=pidlFolder;
5100 hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
5101 ok(hr==S_OK,"Got 0x%08x\n", hr);
5102 IContextMenu_Release(cmenu);
5103 status = RegOpenKeyExA(HKEY_CLASSES_ROOT,"*",0,KEY_READ,keys);
5104 if(status==ERROR_SUCCESS){
5105 for(i=1;i<16;i++)
5106 keys[i]=keys[0];
5107 cminfo.aKeys=keys;
5108 cminfo.cKeys=16;
5109 hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
5110 RegCloseKey(keys[0]);
5111 ok(hr==S_OK,"Got 0x%08x\n", hr);
5112 IContextMenu_Release(cmenu);
5115 ILFree(pidlFolder);
5116 IShellFolder_Release(folder);
5118 IShellFolder_Release(desktop);
5119 ILFree(pidl);
5120 Cleanup();
5123 static void test_SHCreateShellFolderView(void)
5125 HRESULT hr;
5126 IShellView *psv;
5127 SFV_CREATE sfvc;
5128 IShellFolder *desktop;
5129 ULONG refCount;
5131 if (!pSHCreateShellFolderView)
5133 win_skip("SHCreateShellFolderView missing.\n");
5134 return;
5137 hr = SHGetDesktopFolder(&desktop);
5138 ok(hr == S_OK, "got (0x%08x)\n", hr);
5140 if (0)
5142 /* crash on win7 */
5143 pSHCreateShellFolderView(NULL, NULL);
5146 psv = (void *)0xdeadbeef;
5147 hr = pSHCreateShellFolderView(NULL, &psv);
5148 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
5149 ok(psv == NULL, "psv = %p\n", psv);
5151 memset(&sfvc, 0, sizeof(sfvc));
5152 psv = (void *)0xdeadbeef;
5153 hr = pSHCreateShellFolderView(&sfvc, &psv);
5154 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
5155 ok(psv == NULL, "psv = %p\n", psv);
5157 memset(&sfvc, 0, sizeof(sfvc));
5158 sfvc.cbSize = sizeof(sfvc) - 1;
5159 psv = (void *)0xdeadbeef;
5160 hr = pSHCreateShellFolderView(&sfvc, &psv);
5161 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
5162 ok(psv == NULL, "psv = %p\n", psv);
5164 memset(&sfvc, 0, sizeof(sfvc));
5165 sfvc.cbSize = sizeof(sfvc) + 1;
5166 psv = (void *)0xdeadbeef;
5167 hr = pSHCreateShellFolderView(&sfvc, &psv);
5168 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
5169 ok(psv == NULL, "psv = %p\n", psv);
5171 memset(&sfvc, 0, sizeof(sfvc));
5172 sfvc.cbSize = sizeof(sfvc);
5173 sfvc.pshf = desktop;
5174 psv = NULL;
5175 hr = pSHCreateShellFolderView(&sfvc, &psv);
5176 ok(hr == S_OK, "Got 0x%08x\n", hr);
5177 ok(psv != NULL, "psv = %p\n", psv);
5178 if (psv)
5180 refCount = IShellView_Release(psv);
5181 ok(refCount == 0, "refCount = %u\n", refCount);
5184 IShellFolder_Release(desktop);
5187 static void test_SHCreateShellFolderViewEx(void)
5189 HRESULT hr;
5190 IShellView *psv;
5191 CSFV csfv;
5192 IShellFolder *desktop;
5193 ULONG refCount;
5195 if (!pSHCreateShellFolderViewEx)
5197 win_skip("SHCreateShellFolderViewEx missing.\n");
5198 return;
5201 hr = SHGetDesktopFolder(&desktop);
5202 ok(hr == S_OK, "got (0x%08x)\n", hr);
5204 if (0)
5206 /* crash on win7 */
5207 pSHCreateShellFolderViewEx(NULL, NULL);
5208 pSHCreateShellFolderViewEx(NULL, &psv);
5209 pSHCreateShellFolderViewEx(&csfv, NULL);
5212 memset(&csfv, 0, sizeof(csfv));
5213 csfv.pshf = desktop;
5214 psv = NULL;
5215 hr = pSHCreateShellFolderViewEx(&csfv, &psv);
5216 ok(hr == S_OK, "Got 0x%08x\n", hr);
5217 ok(psv != NULL, "psv = %p\n", psv);
5218 if (psv)
5220 refCount = IShellView_Release(psv);
5221 ok(refCount == 0, "refCount = %u\n", refCount);
5224 memset(&csfv, 0, sizeof(csfv));
5225 csfv.cbSize = sizeof(csfv);
5226 csfv.pshf = desktop;
5227 psv = NULL;
5228 hr = pSHCreateShellFolderViewEx(&csfv, &psv);
5229 ok(hr == S_OK, "Got 0x%08x\n", hr);
5230 ok(psv != NULL, "psv = %p\n", psv);
5231 if (psv)
5233 refCount = IShellView_Release(psv);
5234 ok(refCount == 0, "refCount = %u\n", refCount);
5237 IShellFolder_Release(desktop);
5240 static void test_DataObject(void)
5242 IShellFolder *desktop;
5243 IDataObject *data_obj;
5244 HRESULT hres;
5245 IEnumIDList *peidl;
5246 LPITEMIDLIST apidl;
5247 FORMATETC fmt;
5248 DWORD cf_shellidlist;
5249 STGMEDIUM medium;
5251 SHGetDesktopFolder(&desktop);
5253 hres = IShellFolder_EnumObjects(desktop, NULL,
5254 SHCONTF_NONFOLDERS|SHCONTF_FOLDERS|SHCONTF_INCLUDEHIDDEN, &peidl);
5255 ok(hres == S_OK, "got %x\n", hres);
5257 if(IEnumIDList_Next(peidl, 1, &apidl, NULL) != S_OK) {
5258 skip("no files on desktop - skipping GetDataObject tests\n");
5259 IEnumIDList_Release(peidl);
5260 IShellFolder_Release(desktop);
5261 return;
5263 IEnumIDList_Release(peidl);
5265 hres = IShellFolder_GetUIObjectOf(desktop, NULL, 1, (LPCITEMIDLIST*)&apidl,
5266 &IID_IDataObject, NULL, (void**)&data_obj);
5267 ok(hres == S_OK, "got %x\n", hres);
5268 pILFree(apidl);
5269 IShellFolder_Release(desktop);
5271 cf_shellidlist = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW);
5272 fmt.cfFormat = cf_shellidlist;
5273 fmt.ptd = NULL;
5274 fmt.dwAspect = DVASPECT_CONTENT;
5275 fmt.lindex = -1;
5276 fmt.tymed = TYMED_HGLOBAL;
5277 hres = IDataObject_QueryGetData(data_obj, &fmt);
5278 ok(hres == S_OK, "got %x\n", hres);
5280 fmt.tymed = TYMED_HGLOBAL | TYMED_ISTREAM;
5281 hres = IDataObject_QueryGetData(data_obj, &fmt);
5282 ok(hres == S_OK, "got %x\n", hres);
5284 fmt.tymed = TYMED_ISTREAM;
5285 hres = IDataObject_QueryGetData(data_obj, &fmt);
5286 todo_wine ok(hres == S_FALSE, "got %x\n", hres);
5288 fmt.tymed = TYMED_HGLOBAL | TYMED_ISTREAM;
5289 hres = IDataObject_GetData(data_obj, &fmt, &medium);
5290 ok(hres == S_OK, "got %x\n", hres);
5291 ok(medium.tymed == TYMED_HGLOBAL, "medium.tymed = %x\n", medium.tymed);
5292 ReleaseStgMedium(&medium);
5294 IDataObject_Release(data_obj);
5297 START_TEST(shlfolder)
5299 init_function_pointers();
5300 /* if OleInitialize doesn't get called, ParseDisplayName returns
5301 CO_E_NOTINITIALIZED for malformed directory names on win2k. */
5302 OleInitialize(NULL);
5304 test_ParseDisplayName();
5305 test_SHParseDisplayName();
5306 test_BindToObject();
5307 test_EnumObjects_and_CompareIDs();
5308 test_GetDisplayName();
5309 test_GetAttributesOf();
5310 test_SHGetPathFromIDList();
5311 test_CallForAttributes();
5312 test_FolderShortcut();
5313 test_ITEMIDLIST_format();
5314 test_SHGetFolderPathA();
5315 test_SHGetFolderPathAndSubDirA();
5316 test_LocalizedNames();
5317 test_SHCreateShellItem();
5318 test_SHCreateShellItemArray();
5319 test_ShellItemArrayEnumItems();
5320 test_desktop_IPersist();
5321 test_GetUIObject();
5322 test_SHSimpleIDListFromPath();
5323 test_ParseDisplayNamePBC();
5324 test_SHGetNameFromIDList();
5325 test_SHGetItemFromDataObject();
5326 test_SHGetIDListFromObject();
5327 test_SHGetItemFromObject();
5328 test_ShellItemCompare();
5329 test_SHChangeNotify(FALSE);
5330 test_SHChangeNotify(TRUE);
5331 test_ShellItemBindToHandler();
5332 test_ShellItemGetAttributes();
5333 test_ShellItemArrayGetAttributes();
5334 test_SHCreateDefaultContextMenu();
5335 test_SHCreateShellFolderView();
5336 test_SHCreateShellFolderViewEx();
5337 test_DataObject();
5339 OleUninitialize();