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
40 #include "wine/test.h"
43 DEFINE_GUID(IID_IParentAndItem, 0xB3A4B685, 0xB685, 0x4805, 0x99,0xD9, 0x5D,0xEA,0xD2,0x87,0x32,0x36);
47 static HRESULT (WINAPI *pSHBindToParent)(LPCITEMIDLIST, REFIID, LPVOID*, LPCITEMIDLIST*);
48 static HRESULT (WINAPI *pSHGetFolderPathA)(HWND, int, HANDLE, DWORD, LPSTR);
49 static HRESULT (WINAPI *pSHGetFolderPathAndSubDirA)(HWND, int, HANDLE, DWORD, LPCSTR, LPSTR);
50 static BOOL (WINAPI *pSHGetPathFromIDListW)(LPCITEMIDLIST,LPWSTR);
51 static HRESULT (WINAPI *pSHGetSpecialFolderLocation)(HWND, int, LPITEMIDLIST *);
52 static BOOL (WINAPI *pSHGetSpecialFolderPathA)(HWND, LPSTR, int, BOOL);
53 static BOOL (WINAPI *pSHGetSpecialFolderPathW)(HWND, LPWSTR, int, BOOL);
54 static HRESULT (WINAPI *pStrRetToBufW)(STRRET*,LPCITEMIDLIST,LPWSTR,UINT);
55 static LPITEMIDLIST (WINAPI *pILFindLastID)(LPCITEMIDLIST);
56 static void (WINAPI *pILFree)(LPITEMIDLIST);
57 static BOOL (WINAPI *pILIsEqual)(LPCITEMIDLIST, LPCITEMIDLIST);
58 static HRESULT (WINAPI *pSHCreateItemFromIDList)(PCIDLIST_ABSOLUTE pidl, REFIID riid, void **ppv);
59 static HRESULT (WINAPI *pSHCreateItemFromParsingName)(PCWSTR,IBindCtx*,REFIID,void**);
60 static HRESULT (WINAPI *pSHCreateShellItem)(LPCITEMIDLIST,IShellFolder*,LPCITEMIDLIST,IShellItem**);
61 static HRESULT (WINAPI *pSHCreateShellItemArray)(LPCITEMIDLIST,IShellFolder*,UINT,LPCITEMIDLIST*,IShellItemArray**);
62 static HRESULT (WINAPI *pSHCreateShellItemArrayFromDataObject)(IDataObject*, REFIID, void **);
63 static HRESULT (WINAPI *pSHCreateShellItemArrayFromShellItem)(IShellItem*, REFIID, void **);
64 static LPITEMIDLIST (WINAPI *pILCombine)(LPCITEMIDLIST,LPCITEMIDLIST);
65 static HRESULT (WINAPI *pSHParseDisplayName)(LPCWSTR,IBindCtx*,LPITEMIDLIST*,SFGAOF,SFGAOF*);
66 static LPITEMIDLIST (WINAPI *pSHSimpleIDListFromPathAW)(LPCVOID);
67 static HRESULT (WINAPI *pSHGetNameFromIDList)(PCIDLIST_ABSOLUTE,SIGDN,PWSTR*);
68 static HRESULT (WINAPI *pSHGetItemFromDataObject)(IDataObject*,DATAOBJ_GET_ITEM_FLAGS,REFIID,void**);
69 static HRESULT (WINAPI *pSHGetIDListFromObject)(IUnknown*, PIDLIST_ABSOLUTE*);
70 static HRESULT (WINAPI *pSHGetItemFromObject)(IUnknown*,REFIID,void**);
72 static int strcmp_wa(LPCWSTR strw, const char *stra)
75 WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL);
76 return lstrcmpA(stra, buf);
79 static void init_function_pointers(void)
85 hmod = GetModuleHandleA("shell32.dll");
87 #define MAKEFUNC(f) (p##f = (void*)GetProcAddress(hmod, #f))
88 MAKEFUNC(SHBindToParent);
89 MAKEFUNC(SHCreateItemFromIDList);
90 MAKEFUNC(SHCreateItemFromParsingName);
91 MAKEFUNC(SHCreateShellItem);
92 MAKEFUNC(SHCreateShellItemArray);
93 MAKEFUNC(SHCreateShellItemArrayFromDataObject);
94 MAKEFUNC(SHCreateShellItemArrayFromShellItem);
95 MAKEFUNC(SHGetFolderPathA);
96 MAKEFUNC(SHGetFolderPathAndSubDirA);
97 MAKEFUNC(SHGetPathFromIDListW);
98 MAKEFUNC(SHGetSpecialFolderPathA);
99 MAKEFUNC(SHGetSpecialFolderPathW);
100 MAKEFUNC(SHGetSpecialFolderLocation);
101 MAKEFUNC(SHParseDisplayName);
102 MAKEFUNC(SHGetNameFromIDList);
103 MAKEFUNC(SHGetItemFromDataObject);
104 MAKEFUNC(SHGetIDListFromObject);
105 MAKEFUNC(SHGetItemFromObject);
108 #define MAKEFUNC_ORD(f, ord) (p##f = (void*)GetProcAddress(hmod, (LPSTR)(ord)))
109 MAKEFUNC_ORD(ILFindLastID, 16);
110 MAKEFUNC_ORD(ILIsEqual, 21);
111 MAKEFUNC_ORD(ILCombine, 25);
112 MAKEFUNC_ORD(ILFree, 155);
113 MAKEFUNC_ORD(SHSimpleIDListFromPathAW, 162);
116 /* test named exports */
117 ptr = GetProcAddress(hmod, "ILFree");
118 ok(broken(ptr == 0) || ptr != 0, "expected named export for ILFree\n");
121 #define TESTNAMED(f) \
122 ptr = (void*)GetProcAddress(hmod, #f); \
123 ok(ptr != 0, "expected named export for " #f "\n");
125 TESTNAMED(ILAppendID);
127 TESTNAMED(ILCloneFirst);
128 TESTNAMED(ILCombine);
129 TESTNAMED(ILCreateFromPath);
130 TESTNAMED(ILCreateFromPathA);
131 TESTNAMED(ILCreateFromPathW);
132 TESTNAMED(ILFindChild);
133 TESTNAMED(ILFindLastID);
134 TESTNAMED(ILGetNext);
135 TESTNAMED(ILGetSize);
136 TESTNAMED(ILIsEqual);
137 TESTNAMED(ILIsParent);
138 TESTNAMED(ILRemoveLastID);
139 TESTNAMED(ILSaveToStream);
143 hmod = GetModuleHandleA("shlwapi.dll");
144 pStrRetToBufW = (void*)GetProcAddress(hmod, "StrRetToBufW");
146 hr = SHGetMalloc(&ppM);
147 ok(hr == S_OK, "SHGetMalloc failed %08x\n", hr);
150 static void test_ParseDisplayName(void)
153 IShellFolder *IDesktopFolder;
154 static const char *cNonExistDir1A = "c:\\nonexist_subdir";
155 static const char *cNonExistDir2A = "c:\\\\nonexist_subdir";
156 static const char *cInetTestA = "http:\\yyy";
157 static const char *cInetTest2A = "xx:yyy";
159 WCHAR cTestDirW [MAX_PATH] = {0};
163 hr = SHGetDesktopFolder(&IDesktopFolder);
164 ok(hr == S_OK, "Expected SHGetDesktopFolder to return S_OK, got 0x%08x\n", hr);
165 if(hr != S_OK) return;
167 /* Tests crash on W2K and below (SHCreateShellItem available as of XP) */
168 if (pSHCreateShellItem)
170 /* null name and pidl */
171 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
172 NULL, NULL, NULL, NULL, NULL, 0);
173 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
176 newPIDL = (ITEMIDLIST*)0xdeadbeef;
177 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
178 NULL, NULL, NULL, NULL, &newPIDL, 0);
179 ok(newPIDL == 0, "expected null, got %p\n", newPIDL);
180 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
183 win_skip("Tests would crash on W2K and below\n");
185 MultiByteToWideChar(CP_ACP, 0, cInetTestA, -1, cTestDirW, MAX_PATH);
186 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
187 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
188 todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
189 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
192 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
193 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
194 IMalloc_Free(ppM, newPIDL);
197 MultiByteToWideChar(CP_ACP, 0, cInetTest2A, -1, cTestDirW, MAX_PATH);
198 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
199 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
200 todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
201 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
204 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
205 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
206 IMalloc_Free(ppM, newPIDL);
209 res = GetFileAttributesA(cNonExistDir1A);
210 if(res != INVALID_FILE_ATTRIBUTES)
212 skip("Test directory unexpectedly exists\n");
216 MultiByteToWideChar(CP_ACP, 0, cNonExistDir1A, -1, cTestDirW, MAX_PATH);
217 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
218 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
219 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL),
220 "ParseDisplayName returned %08x, expected 80070002 or E_FAIL\n", hr);
222 res = GetFileAttributesA(cNonExistDir2A);
223 if(res != INVALID_FILE_ATTRIBUTES)
225 skip("Test directory unexpectedly exists\n");
229 MultiByteToWideChar(CP_ACP, 0, cNonExistDir2A, -1, cTestDirW, MAX_PATH);
230 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
231 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
232 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL) || (hr == E_INVALIDARG),
233 "ParseDisplayName returned %08x, expected 80070002, E_FAIL or E_INVALIDARG\n", hr);
235 /* I thought that perhaps the DesktopFolder's ParseDisplayName would recognize the
236 * path corresponding to CSIDL_PERSONAL and return a CLSID_MyDocuments PIDL. Turns
237 * out it doesn't. The magic seems to happen in the file dialogs, then. */
238 if (!pSHGetSpecialFolderPathW || !pILFindLastID)
240 win_skip("SHGetSpecialFolderPathW and/or ILFindLastID are not available\n");
244 bRes = pSHGetSpecialFolderPathW(NULL, cTestDirW, CSIDL_PERSONAL, FALSE);
245 ok(bRes, "SHGetSpecialFolderPath(CSIDL_PERSONAL) failed! %u\n", GetLastError());
246 if (!bRes) goto finished;
248 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
249 ok(hr == S_OK, "DesktopFolder->ParseDisplayName failed. hr = %08x.\n", hr);
250 if (hr != S_OK) goto finished;
252 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x31 ||
253 pILFindLastID(newPIDL)->mkid.abID[0] == 0xb1, /* Win98 */
254 "Last pidl should be of type PT_FOLDER or PT_IESPECIAL2, but is: %02x\n",
255 pILFindLastID(newPIDL)->mkid.abID[0]);
256 IMalloc_Free(ppM, newPIDL);
259 IShellFolder_Release(IDesktopFolder);
262 /* creates a file with the specified name for tests */
263 static void CreateTestFile(const CHAR *name)
268 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
269 if (file != INVALID_HANDLE_VALUE)
271 WriteFile(file, name, strlen(name), &written, NULL);
272 WriteFile(file, "\n", strlen("\n"), &written, NULL);
278 /* initializes the tests */
279 static void CreateFilesFolders(void)
281 CreateDirectoryA(".\\testdir", NULL);
282 CreateDirectoryA(".\\testdir\\test.txt", NULL);
283 CreateTestFile (".\\testdir\\test1.txt ");
284 CreateTestFile (".\\testdir\\test2.txt ");
285 CreateTestFile (".\\testdir\\test3.txt ");
286 CreateDirectoryA(".\\testdir\\testdir2 ", NULL);
287 CreateDirectoryA(".\\testdir\\testdir2\\subdir", NULL);
290 /* cleans after tests */
291 static void Cleanup(void)
293 DeleteFileA(".\\testdir\\test1.txt");
294 DeleteFileA(".\\testdir\\test2.txt");
295 DeleteFileA(".\\testdir\\test3.txt");
296 RemoveDirectoryA(".\\testdir\\test.txt");
297 RemoveDirectoryA(".\\testdir\\testdir2\\subdir");
298 RemoveDirectoryA(".\\testdir\\testdir2");
299 RemoveDirectoryA(".\\testdir");
304 static void test_EnumObjects(IShellFolder *iFolder)
306 IEnumIDList *iEnumList;
307 LPITEMIDLIST newPIDL, idlArr[10];
312 static const WORD iResults [5][5] =
321 #define SFGAO_testfor SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | SFGAO_CAPABILITYMASK
322 /* Don't test for SFGAO_HASSUBFOLDER since we return real state and native cached */
323 static const ULONG attrs[5] =
325 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
326 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
327 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
328 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
329 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
332 hr = IShellFolder_EnumObjects(iFolder, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &iEnumList);
333 ok(hr == S_OK, "EnumObjects failed %08x\n", hr);
335 /* This is to show that, contrary to what is said on MSDN, on IEnumIDList::Next,
336 * the filesystem shellfolders return S_OK even if less than 'celt' items are
337 * returned (in contrast to S_FALSE). We have to do it in a loop since WinXP
338 * only ever returns a single entry per call. */
339 while (IEnumIDList_Next(iEnumList, 10-i, &idlArr[i], &NumPIDLs) == S_OK)
341 ok (i == 5, "i: %d\n", i);
343 hr = IEnumIDList_Release(iEnumList);
344 ok(hr == S_OK, "IEnumIDList_Release failed %08x\n", hr);
346 /* Sort them first in case of wrong order from system */
347 for (i=0;i<5;i++) for (j=0;j<5;j++)
348 if ((SHORT)IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]) < 0)
351 idlArr[i] = idlArr[j];
355 for (i=0;i<5;i++) for (j=0;j<5;j++)
357 hr = IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]);
358 ok(hr == iResults[i][j], "Got %x expected [%d]-[%d]=%x\n", hr, i, j, iResults[i][j]);
362 for (i = 0; i < 5; i++)
365 #define SFGAO_VISTA SFGAO_DROPTARGET | SFGAO_CANLINK | SFGAO_CANCOPY
366 /* Native returns all flags no matter what we ask for */
367 flags = SFGAO_CANCOPY;
368 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
369 flags &= SFGAO_testfor;
370 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
371 ok(flags == (attrs[i]) ||
372 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR) || /* Win9x, NT4 */
373 flags == ((attrs[i] & ~SFGAO_CAPABILITYMASK) | SFGAO_VISTA), /* Vista and higher */
374 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
376 flags = SFGAO_testfor;
377 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
378 flags &= SFGAO_testfor;
379 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
380 ok(flags == attrs[i] ||
381 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR), /* Win9x, NT4 */
382 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
386 IMalloc_Free(ppM, idlArr[i]);
389 static void test_BindToObject(void)
393 IShellFolder *psfDesktop, *psfChild, *psfMyComputer, *psfSystemDir;
394 SHITEMID emptyitem = { 0, { 0 } };
395 LPITEMIDLIST pidlMyComputer, pidlSystemDir, pidlEmpty = (LPITEMIDLIST)&emptyitem;
396 WCHAR wszSystemDir[MAX_PATH];
397 char szSystemDir[MAX_PATH];
398 WCHAR wszMyComputer[] = {
399 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
400 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
402 /* The following tests shows that BindToObject should fail with E_INVALIDARG if called
403 * with an empty pidl. This is tested for Desktop, MyComputer and the FS ShellFolder
405 hr = SHGetDesktopFolder(&psfDesktop);
406 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
407 if (hr != S_OK) return;
409 hr = IShellFolder_BindToObject(psfDesktop, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
410 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
412 hr = IShellFolder_BindToObject(psfDesktop, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
413 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
415 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
416 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
418 IShellFolder_Release(psfDesktop);
422 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
423 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
424 IShellFolder_Release(psfDesktop);
425 IMalloc_Free(ppM, pidlMyComputer);
426 if (hr != S_OK) return;
428 hr = IShellFolder_BindToObject(psfMyComputer, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
429 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
433 /* this call segfaults on 98SE */
434 hr = IShellFolder_BindToObject(psfMyComputer, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
435 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
438 cChars = GetSystemDirectoryA(szSystemDir, MAX_PATH);
439 ok (cChars > 0 && cChars < MAX_PATH, "GetSystemDirectoryA failed! LastError: %u\n", GetLastError());
440 if (cChars == 0 || cChars >= MAX_PATH) {
441 IShellFolder_Release(psfMyComputer);
444 MultiByteToWideChar(CP_ACP, 0, szSystemDir, -1, wszSystemDir, MAX_PATH);
446 hr = IShellFolder_ParseDisplayName(psfMyComputer, NULL, NULL, wszSystemDir, NULL, &pidlSystemDir, NULL);
447 ok (hr == S_OK, "MyComputers's ParseDisplayName failed to parse the SystemDirectory! hr = %08x\n", hr);
449 IShellFolder_Release(psfMyComputer);
453 hr = IShellFolder_BindToObject(psfMyComputer, pidlSystemDir, NULL, &IID_IShellFolder, (LPVOID*)&psfSystemDir);
454 ok (hr == S_OK, "MyComputer failed to bind to a FileSystem ShellFolder! hr = %08x\n", hr);
455 IShellFolder_Release(psfMyComputer);
456 IMalloc_Free(ppM, pidlSystemDir);
457 if (hr != S_OK) return;
459 hr = IShellFolder_BindToObject(psfSystemDir, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
460 ok (hr == E_INVALIDARG,
461 "FileSystem ShellFolder's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
465 /* this call segfaults on 98SE */
466 hr = IShellFolder_BindToObject(psfSystemDir, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
467 ok (hr == E_INVALIDARG,
468 "FileSystem ShellFolder's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
471 IShellFolder_Release(psfSystemDir);
474 /* Based on PathAddBackslashW from dlls/shlwapi/path.c */
475 static LPWSTR myPathAddBackslashW( LPWSTR lpszPath )
479 if (!lpszPath || (iLen = lstrlenW(lpszPath)) >= MAX_PATH)
485 if (lpszPath[-1] != '\\')
494 static void test_GetDisplayName(void)
499 WCHAR wszTestFile[MAX_PATH], wszTestFile2[MAX_PATH];
500 char szTestFile[MAX_PATH], szTestDir[MAX_PATH];
503 LPSHELLFOLDER psfDesktop, psfPersonal;
505 SHITEMID emptyitem = { 0, { 0 } };
506 LPITEMIDLIST pidlTestFile, pidlEmpty = (LPITEMIDLIST)&emptyitem;
507 LPCITEMIDLIST pidlLast;
508 static const CHAR szFileName[] = "winetest.foo";
509 static const WCHAR wszFileName[] = { 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
510 static const WCHAR wszDirName[] = { 'w','i','n','e','t','e','s','t',0 };
512 /* I'm trying to figure if there is a functional difference between calling
513 * SHGetPathFromIDListW and calling GetDisplayNameOf(SHGDN_FORPARSING) after
514 * binding to the shellfolder. One thing I thought of was that perhaps
515 * SHGetPathFromIDListW would be able to get the path to a file, which does
516 * not exist anymore, while the other method wouldn't. It turns out there's
517 * no functional difference in this respect.
520 if(!pSHGetSpecialFolderPathA) {
521 win_skip("SHGetSpecialFolderPathA is not available\n");
525 /* First creating a directory in MyDocuments and a file in this directory. */
526 result = pSHGetSpecialFolderPathA(NULL, szTestDir, CSIDL_PERSONAL, FALSE);
527 ok(result, "SHGetSpecialFolderPathA failed! Last error: %u\n", GetLastError());
530 /* Use ANSI file functions so this works on Windows 9x */
531 lstrcatA(szTestDir, "\\winetest");
532 CreateDirectoryA(szTestDir, NULL);
533 attr=GetFileAttributesA(szTestDir);
534 if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY))
536 ok(0, "unable to create the '%s' directory\n", szTestDir);
540 lstrcpyA(szTestFile, szTestDir);
541 lstrcatA(szTestFile, "\\");
542 lstrcatA(szTestFile, szFileName);
543 hTestFile = CreateFileA(szTestFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
544 ok((hTestFile != INVALID_HANDLE_VALUE), "CreateFileA failed! Last error: %u\n", GetLastError());
545 if (hTestFile == INVALID_HANDLE_VALUE) return;
546 CloseHandle(hTestFile);
548 /* Getting an itemidlist for the file. */
549 hr = SHGetDesktopFolder(&psfDesktop);
550 ok(hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
551 if (hr != S_OK) return;
553 MultiByteToWideChar(CP_ACP, 0, szTestFile, -1, wszTestFile, MAX_PATH);
555 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
556 ok(hr == S_OK, "Desktop->ParseDisplayName failed! hr = %08x\n", hr);
558 IShellFolder_Release(psfDesktop);
562 pidlLast = pILFindLastID(pidlTestFile);
563 ok(pidlLast->mkid.cb >=76 ||
564 broken(pidlLast->mkid.cb == 28) || /* W2K */
565 broken(pidlLast->mkid.cb == 40), /* Win9x, WinME */
566 "Expected pidl length of at least 76, got %d.\n", pidlLast->mkid.cb);
567 if (pidlLast->mkid.cb >= 28) {
568 ok(!lstrcmpA((CHAR*)&pidlLast->mkid.abID[12], szFileName),
569 "Filename should be stored as ansi-string at this position!\n");
571 /* WinXP and up store the filenames as both ANSI and UNICODE in the pidls */
572 if (pidlLast->mkid.cb >= 76) {
573 ok(!lstrcmpW((WCHAR*)&pidlLast->mkid.abID[46], wszFileName) ||
574 (pidlLast->mkid.cb >= 94 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[64], wszFileName)) || /* Vista */
575 (pidlLast->mkid.cb >= 98 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[68], wszFileName)), /* Win7 */
576 "Filename should be stored as wchar-string at this position!\n");
579 /* It seems as if we cannot bind to regular files on windows, but only directories.
581 hr = IShellFolder_BindToObject(psfDesktop, pidlTestFile, NULL, &IID_IUnknown, (VOID**)&psfFile);
583 ok (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
584 hr == E_NOTIMPL || /* Vista */
585 broken(hr == S_OK), /* Win9x, W2K */
588 IShellFolder_Release(psfFile);
591 if (!pSHBindToParent)
593 win_skip("SHBindToParent is missing\n");
594 DeleteFileA(szTestFile);
595 RemoveDirectoryA(szTestDir);
599 /* Some tests for IShellFolder::SetNameOf */
600 if (pSHGetFolderPathAndSubDirA)
602 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
603 ok(hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
605 /* It's ok to use this fixed path. Call will fail anyway. */
606 WCHAR wszAbsoluteFilename[] = { 'C',':','\\','w','i','n','e','t','e','s','t', 0 };
607 LPITEMIDLIST pidlNew;
609 /* The pidl returned through the last parameter of SetNameOf is a simple one. */
610 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlLast, wszDirName, SHGDN_NORMAL, &pidlNew);
611 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
614 ok (((LPITEMIDLIST)((LPBYTE)pidlNew+pidlNew->mkid.cb))->mkid.cb == 0,
615 "pidl returned from SetNameOf should be simple!\n");
617 /* Passing an absolute path to SetNameOf fails. The HRESULT code indicates that SetNameOf
618 * is implemented on top of SHFileOperation in WinXP. */
619 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszAbsoluteFilename,
620 SHGDN_FORPARSING, NULL);
621 ok (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED), "SetNameOf succeeded! hr = %08x\n", hr);
623 /* Rename the file back to its original name. SetNameOf ignores the fact, that the
624 * SHGDN flags specify an absolute path. */
625 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszFileName, SHGDN_FORPARSING, NULL);
626 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
631 IShellFolder_Release(psfPersonal);
635 win_skip("Avoid needs of interaction on Win2k\n");
637 /* Deleting the file and the directory */
638 DeleteFileA(szTestFile);
639 RemoveDirectoryA(szTestDir);
641 /* SHGetPathFromIDListW still works, although the file is not present anymore. */
642 if (pSHGetPathFromIDListW)
644 result = pSHGetPathFromIDListW(pidlTestFile, wszTestFile2);
645 ok (result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
646 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "SHGetPathFromIDListW returns incorrect path!\n");
649 /* SHBindToParent fails, if called with a NULL PIDL. */
650 hr = pSHBindToParent(NULL, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
651 ok (hr != S_OK, "SHBindToParent(NULL) should fail!\n");
653 /* But it succeeds with an empty PIDL. */
654 hr = pSHBindToParent(pidlEmpty, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
655 ok (hr == S_OK, "SHBindToParent(empty PIDL) should succeed! hr = %08x\n", hr);
656 ok (pidlLast == pidlEmpty, "The last element of an empty PIDL should be the PIDL itself!\n");
658 IShellFolder_Release(psfPersonal);
660 /* Binding to the folder and querying the display name of the file also works. */
661 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
662 ok (hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
664 IShellFolder_Release(psfDesktop);
668 /* This test shows that Windows doesn't allocate a new pidlLast, but returns a pointer into
669 * pidlTestFile (In accordance with MSDN). */
670 ok (pILFindLastID(pidlTestFile) == pidlLast,
671 "SHBindToParent doesn't return the last id of the pidl param!\n");
673 hr = IShellFolder_GetDisplayNameOf(psfPersonal, pidlLast, SHGDN_FORPARSING, &strret);
674 ok (hr == S_OK, "Personal->GetDisplayNameOf failed! hr = %08x\n", hr);
676 IShellFolder_Release(psfDesktop);
677 IShellFolder_Release(psfPersonal);
683 hr = pStrRetToBufW(&strret, pidlLast, wszTestFile2, MAX_PATH);
684 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
685 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "GetDisplayNameOf returns incorrect path!\n");
688 ILFree(pidlTestFile);
689 IShellFolder_Release(psfDesktop);
690 IShellFolder_Release(psfPersonal);
693 static void test_CallForAttributes(void)
699 LPSHELLFOLDER psfDesktop;
700 LPITEMIDLIST pidlMyDocuments;
701 DWORD dwAttributes, dwCallForAttributes, dwOrigAttributes, dwOrigCallForAttributes;
702 static const WCHAR wszAttributes[] = { 'A','t','t','r','i','b','u','t','e','s',0 };
703 static const WCHAR wszCallForAttributes[] = {
704 'C','a','l','l','F','o','r','A','t','t','r','i','b','u','t','e','s',0 };
705 static const WCHAR wszMyDocumentsKey[] = {
706 'C','L','S','I','D','\\','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-',
707 '1','1','D','0','-','9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',
708 '\\','S','h','e','l','l','F','o','l','d','e','r',0 };
709 WCHAR wszMyDocuments[] = {
710 ':',':','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-','1','1','D','0','-',
711 '9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',0 };
713 /* For the root of a namespace extension, the attributes are not queried by binding
714 * to the object and calling GetAttributesOf. Instead, the attributes are read from
715 * the registry value HKCR/CLSID/{...}/ShellFolder/Attributes. This is documented on MSDN.
717 * The MyDocuments shellfolder on WinXP has a HKCR/CLSID/{...}/ShellFolder/CallForAttributes
718 * value. It seems that if the folder is queried for one of the flags set in CallForAttributes,
719 * the shell does bind to the folder object and calls GetAttributesOf. This is not documented
720 * on MSDN. This test is meant to document the observed behaviour on WinXP SP2.
722 hr = SHGetDesktopFolder(&psfDesktop);
723 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
724 if (hr != S_OK) return;
726 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyDocuments, NULL,
727 &pidlMyDocuments, NULL);
729 broken(hr == E_INVALIDARG), /* Win95, NT4 */
730 "Desktop's ParseDisplayName failed to parse MyDocuments's CLSID! hr = %08x\n", hr);
732 IShellFolder_Release(psfDesktop);
736 dwAttributes = 0xffffffff;
737 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
738 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
739 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
741 /* We need the following setup (as observed on WinXP SP2), for the tests to make sense. */
742 ok (dwAttributes & SFGAO_FILESYSTEM, "SFGAO_FILESYSTEM attribute is not set for MyDocuments!\n");
743 ok (!(dwAttributes & SFGAO_ISSLOW), "SFGAO_ISSLOW attribute is set for MyDocuments!\n");
744 ok (!(dwAttributes & SFGAO_GHOSTED), "SFGAO_GHOSTED attribute is set for MyDocuments!\n");
746 /* We don't have the MyDocuments shellfolder in wine yet, and thus we don't have the registry
747 * key. So the test will return at this point, if run on wine.
749 lResult = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszMyDocumentsKey, 0, KEY_WRITE|KEY_READ, &hKey);
750 ok (lResult == ERROR_SUCCESS ||
751 lResult == ERROR_ACCESS_DENIED,
752 "RegOpenKeyEx failed! result: %08x\n", lResult);
753 if (lResult != ERROR_SUCCESS) {
754 if (lResult == ERROR_ACCESS_DENIED)
755 skip("Not enough rights to open the registry key\n");
756 IMalloc_Free(ppM, pidlMyDocuments);
757 IShellFolder_Release(psfDesktop);
761 /* Query MyDocuments' Attributes value, to be able to restore it later. */
762 dwSize = sizeof(DWORD);
763 lResult = RegQueryValueExW(hKey, wszAttributes, NULL, NULL, (LPBYTE)&dwOrigAttributes, &dwSize);
764 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
765 if (lResult != ERROR_SUCCESS) {
767 IMalloc_Free(ppM, pidlMyDocuments);
768 IShellFolder_Release(psfDesktop);
772 /* Query MyDocuments' CallForAttributes value, to be able to restore it later. */
773 dwSize = sizeof(DWORD);
774 lResult = RegQueryValueExW(hKey, wszCallForAttributes, NULL, NULL,
775 (LPBYTE)&dwOrigCallForAttributes, &dwSize);
776 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
777 if (lResult != ERROR_SUCCESS) {
779 IMalloc_Free(ppM, pidlMyDocuments);
780 IShellFolder_Release(psfDesktop);
784 /* Define via the Attributes value that MyDocuments attributes are SFGAO_ISSLOW and
785 * SFGAO_GHOSTED and that MyDocuments should be called for the SFGAO_ISSLOW and
786 * SFGAO_FILESYSTEM attributes. */
787 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED;
788 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwAttributes, sizeof(DWORD));
789 dwCallForAttributes = SFGAO_ISSLOW|SFGAO_FILESYSTEM;
790 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
791 (LPBYTE)&dwCallForAttributes, sizeof(DWORD));
793 /* Although it is not set in CallForAttributes, the SFGAO_GHOSTED flag is reset by
794 * GetAttributesOf. It seems that once there is a single attribute queried, for which
795 * CallForAttributes is set, all flags are taken from the GetAttributesOf call and
796 * the flags in Attributes are ignored.
798 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED|SFGAO_FILESYSTEM;
799 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
800 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
801 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
803 ok (dwAttributes == SFGAO_FILESYSTEM,
804 "Desktop->GetAttributes(MyDocuments) returned unexpected attributes: %08x\n",
807 /* Restore MyDocuments' original Attributes and CallForAttributes registry values */
808 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwOrigAttributes, sizeof(DWORD));
809 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
810 (LPBYTE)&dwOrigCallForAttributes, sizeof(DWORD));
812 IMalloc_Free(ppM, pidlMyDocuments);
813 IShellFolder_Release(psfDesktop);
816 static void test_GetAttributesOf(void)
819 LPSHELLFOLDER psfDesktop, psfMyComputer;
820 SHITEMID emptyitem = { 0, { 0 } };
821 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
822 LPITEMIDLIST pidlMyComputer;
824 static const DWORD desktopFlags[] = {
826 SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSANCESTOR |
827 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
829 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_STREAM | SFGAO_FILESYSANCESTOR |
830 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
831 /* WinMe, Win9x, WinNT*/
832 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSANCESTOR |
833 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
835 static const DWORD myComputerFlags[] = {
837 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
838 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
840 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_STREAM |
841 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
842 /* WinMe, Win9x, WinNT */
843 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
844 SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
845 /* Win95, WinNT when queried directly */
846 SFGAO_CANLINK | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
847 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
849 WCHAR wszMyComputer[] = {
850 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
851 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
852 char cCurrDirA [MAX_PATH] = {0};
853 WCHAR cCurrDirW [MAX_PATH];
854 static WCHAR cTestDirW[] = {'t','e','s','t','d','i','r',0};
855 IShellFolder *IDesktopFolder, *testIShellFolder;
858 BOOL foundFlagsMatch;
860 hr = SHGetDesktopFolder(&psfDesktop);
861 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
862 if (hr != S_OK) return;
864 /* The Desktop attributes can be queried with a single empty itemidlist, .. */
865 dwFlags = 0xffffffff;
866 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, &pidlEmpty, &dwFlags);
867 ok (hr == S_OK, "Desktop->GetAttributesOf(empty pidl) failed! hr = %08x\n", hr);
868 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
869 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
871 if (desktopFlags[i] == dwFlags)
872 foundFlagsMatch = TRUE;
874 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
876 /* .. or with no itemidlist at all. */
877 dwFlags = 0xffffffff;
878 hr = IShellFolder_GetAttributesOf(psfDesktop, 0, NULL, &dwFlags);
879 ok (hr == S_OK, "Desktop->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
880 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
881 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
883 if (desktopFlags[i] == dwFlags)
884 foundFlagsMatch = TRUE;
886 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
888 /* Testing the attributes of the MyComputer shellfolder */
889 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
890 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
892 IShellFolder_Release(psfDesktop);
896 /* Windows sets the SFGAO_CANLINK flag, when MyComputer is queried via the Desktop
897 * folder object. It doesn't do this, if MyComputer is queried directly (see below).
899 dwFlags = 0xffffffff;
900 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, (LPCITEMIDLIST*)&pidlMyComputer, &dwFlags);
901 ok (hr == S_OK, "Desktop->GetAttributesOf(MyComputer) failed! hr = %08x\n", hr);
902 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
903 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
905 if ((myComputerFlags[i] | SFGAO_CANLINK) == dwFlags)
906 foundFlagsMatch = TRUE;
909 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
911 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
912 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
913 IShellFolder_Release(psfDesktop);
914 IMalloc_Free(ppM, pidlMyComputer);
915 if (hr != S_OK) return;
917 hr = IShellFolder_GetAttributesOf(psfMyComputer, 1, &pidlEmpty, &dwFlags);
919 ok (hr == E_INVALIDARG ||
920 broken(hr == S_OK), /* W2K and earlier */
921 "MyComputer->GetAttributesOf(emtpy pidl) should fail! hr = %08x\n", hr);
923 dwFlags = 0xffffffff;
924 hr = IShellFolder_GetAttributesOf(psfMyComputer, 0, NULL, &dwFlags);
925 ok (hr == S_OK, "MyComputer->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
926 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
927 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
929 if (myComputerFlags[i] == dwFlags)
930 foundFlagsMatch = TRUE;
933 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
935 IShellFolder_Release(psfMyComputer);
937 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
938 len = lstrlenA(cCurrDirA);
941 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_GetAttributesOf\n");
944 if (len > 3 && cCurrDirA[len-1] == '\\')
945 cCurrDirA[len-1] = 0;
947 /* create test directory */
948 CreateFilesFolders();
950 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
952 hr = SHGetDesktopFolder(&IDesktopFolder);
953 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
955 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
956 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
958 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
959 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
961 IMalloc_Free(ppM, newPIDL);
963 /* get relative PIDL */
964 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
965 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
967 /* test the shell attributes of the test directory using the relative PIDL */
968 dwFlags = SFGAO_FOLDER;
969 hr = IShellFolder_GetAttributesOf(testIShellFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
970 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
971 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for relative PIDL: %08x\n", dwFlags);
974 IMalloc_Free(ppM, newPIDL);
976 /* append testdirectory name to path */
977 if (cCurrDirA[len-1] == '\\')
978 cCurrDirA[len-1] = 0;
979 lstrcatA(cCurrDirA, "\\testdir");
980 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
982 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
983 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
985 /* test the shell attributes of the test directory using the absolute PIDL */
986 dwFlags = SFGAO_FOLDER;
987 hr = IShellFolder_GetAttributesOf(IDesktopFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
988 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
989 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for absolute PIDL: %08x\n", dwFlags);
992 IMalloc_Free(ppM, newPIDL);
994 IShellFolder_Release(testIShellFolder);
998 IShellFolder_Release(IDesktopFolder);
1001 static void test_SHGetPathFromIDList(void)
1003 SHITEMID emptyitem = { 0, { 0 } };
1004 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
1005 LPITEMIDLIST pidlMyComputer;
1006 WCHAR wszPath[MAX_PATH], wszDesktop[MAX_PATH];
1009 LPSHELLFOLDER psfDesktop;
1010 WCHAR wszMyComputer[] = {
1011 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
1012 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
1013 WCHAR wszFileName[MAX_PATH];
1014 LPITEMIDLIST pidlTestFile;
1017 static WCHAR wszTestFile[] = {
1018 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
1019 LPITEMIDLIST pidlPrograms;
1021 if(!pSHGetPathFromIDListW || !pSHGetSpecialFolderPathW)
1023 win_skip("SHGetPathFromIDListW() or SHGetSpecialFolderPathW() is missing\n");
1027 /* Calling SHGetPathFromIDListW with no pidl should return the empty string */
1030 result = pSHGetPathFromIDListW(NULL, wszPath);
1031 ok(!result, "Expected failure\n");
1032 ok(!wszPath[0], "Expected empty string\n");
1034 /* Calling SHGetPathFromIDListW with an empty pidl should return the desktop folder's path. */
1035 result = pSHGetSpecialFolderPathW(NULL, wszDesktop, CSIDL_DESKTOP, FALSE);
1036 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOP) failed! Last error: %u\n", GetLastError());
1037 if (!result) return;
1039 /* Check if we are on Win9x */
1040 SetLastError(0xdeadbeef);
1041 lstrcmpiW(wszDesktop, wszDesktop);
1042 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1044 win_skip("Most W-calls are not implemented\n");
1048 result = pSHGetPathFromIDListW(pidlEmpty, wszPath);
1049 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1050 if (!result) return;
1051 ok(!lstrcmpiW(wszDesktop, wszPath), "SHGetPathFromIDListW didn't return desktop path for empty pidl!\n");
1053 /* MyComputer does not map to a filesystem path. SHGetPathFromIDListW should fail. */
1054 hr = SHGetDesktopFolder(&psfDesktop);
1055 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1056 if (hr != S_OK) return;
1058 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1059 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1061 IShellFolder_Release(psfDesktop);
1065 SetLastError(0xdeadbeef);
1068 result = pSHGetPathFromIDListW(pidlMyComputer, wszPath);
1069 ok (!result, "SHGetPathFromIDListW succeeded where it shouldn't!\n");
1070 ok (GetLastError()==0xdeadbeef ||
1071 GetLastError()==ERROR_SUCCESS, /* Vista and higher */
1072 "Unexpected last error from SHGetPathFromIDListW: %u\n", GetLastError());
1073 ok (!wszPath[0], "Expected empty path\n");
1075 IShellFolder_Release(psfDesktop);
1079 IMalloc_Free(ppM, pidlMyComputer);
1081 result = pSHGetSpecialFolderPathW(NULL, wszFileName, CSIDL_DESKTOPDIRECTORY, FALSE);
1082 ok(result, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1084 IShellFolder_Release(psfDesktop);
1087 myPathAddBackslashW(wszFileName);
1088 lstrcatW(wszFileName, wszTestFile);
1089 hTestFile = CreateFileW(wszFileName, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
1090 ok(hTestFile != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: %u\n", GetLastError());
1091 if (hTestFile == INVALID_HANDLE_VALUE) {
1092 IShellFolder_Release(psfDesktop);
1095 CloseHandle(hTestFile);
1097 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
1098 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse filename hr = %08x\n", hr);
1100 IShellFolder_Release(psfDesktop);
1101 DeleteFileW(wszFileName);
1102 IMalloc_Free(ppM, pidlTestFile);
1106 /* This test is to show that the Desktop shellfolder prepends the CSIDL_DESKTOPDIRECTORY
1107 * path for files placed on the desktop, if called with SHGDN_FORPARSING. */
1108 hr = IShellFolder_GetDisplayNameOf(psfDesktop, pidlTestFile, SHGDN_FORPARSING, &strret);
1109 ok (hr == S_OK, "Desktop's GetDisplayNamfOf failed! hr = %08x\n", hr);
1110 IShellFolder_Release(psfDesktop);
1111 DeleteFileW(wszFileName);
1113 IMalloc_Free(ppM, pidlTestFile);
1118 pStrRetToBufW(&strret, pidlTestFile, wszPath, MAX_PATH);
1119 ok(0 == lstrcmpW(wszFileName, wszPath),
1120 "Desktop->GetDisplayNameOf(pidlTestFile, SHGDN_FORPARSING) "
1121 "returned incorrect path for file placed on desktop\n");
1124 result = pSHGetPathFromIDListW(pidlTestFile, wszPath);
1125 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1126 IMalloc_Free(ppM, pidlTestFile);
1127 if (!result) return;
1128 ok(0 == lstrcmpW(wszFileName, wszPath), "SHGetPathFromIDListW returned incorrect path for file placed on desktop\n");
1131 /* Test if we can get the path from the start menu "program files" PIDL. */
1132 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidlPrograms);
1133 ok(hr == S_OK, "SHGetFolderLocation failed: 0x%08x\n", hr);
1135 SetLastError(0xdeadbeef);
1136 result = pSHGetPathFromIDListW(pidlPrograms, wszPath);
1137 IMalloc_Free(ppM, pidlPrograms);
1138 ok(result, "SHGetPathFromIDListW failed\n");
1141 static void test_EnumObjects_and_CompareIDs(void)
1143 ITEMIDLIST *newPIDL;
1144 IShellFolder *IDesktopFolder, *testIShellFolder;
1145 char cCurrDirA [MAX_PATH] = {0};
1146 static const CHAR cTestDirA[] = "\\testdir";
1147 WCHAR cTestDirW[MAX_PATH];
1151 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1152 len = lstrlenA(cCurrDirA);
1155 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_EnumObjects_and_CompareIDs\n");
1158 if(cCurrDirA[len-1] == '\\')
1159 cCurrDirA[len-1] = 0;
1161 lstrcatA(cCurrDirA, cTestDirA);
1162 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cTestDirW, MAX_PATH);
1164 hr = SHGetDesktopFolder(&IDesktopFolder);
1165 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1167 CreateFilesFolders();
1169 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1170 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1172 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1173 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1175 test_EnumObjects(testIShellFolder);
1177 IShellFolder_Release(testIShellFolder);
1181 IMalloc_Free(ppM, newPIDL);
1183 IShellFolder_Release(IDesktopFolder);
1186 /* A simple implementation of an IPropertyBag, which returns fixed values for
1187 * 'Target' and 'Attributes' properties.
1189 static HRESULT WINAPI InitPropertyBag_IPropertyBag_QueryInterface(IPropertyBag *iface, REFIID riid,
1193 return E_INVALIDARG;
1195 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPropertyBag, riid)) {
1198 ok (FALSE, "InitPropertyBag asked for unknown interface!\n");
1199 return E_NOINTERFACE;
1202 IPropertyBag_AddRef(iface);
1206 static ULONG WINAPI InitPropertyBag_IPropertyBag_AddRef(IPropertyBag *iface) {
1210 static ULONG WINAPI InitPropertyBag_IPropertyBag_Release(IPropertyBag *iface) {
1214 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Read(IPropertyBag *iface, LPCOLESTR pszPropName,
1215 VARIANT *pVar, IErrorLog *pErrorLog)
1217 static const WCHAR wszTargetSpecialFolder[] = {
1218 'T','a','r','g','e','t','S','p','e','c','i','a','l','F','o','l','d','e','r',0 };
1219 static const WCHAR wszTarget[] = {
1220 'T','a','r','g','e','t',0 };
1221 static const WCHAR wszAttributes[] = {
1222 'A','t','t','r','i','b','u','t','e','s',0 };
1223 static const WCHAR wszResolveLinkFlags[] = {
1224 'R','e','s','o','l','v','e','L','i','n','k','F','l','a','g','s',0 };
1225 static const WCHAR wszTargetKnownFolder[] = {
1226 'T','a','r','g','e','t','K','n','o','w','n','F','o','l','d','e','r',0 };
1227 static const WCHAR wszCLSID[] = {
1228 'C','L','S','I','D',0 };
1230 if (!lstrcmpW(pszPropName, wszTargetSpecialFolder)) {
1231 ok(V_VT(pVar) == VT_I4 ||
1232 broken(V_VT(pVar) == VT_BSTR), /* Win2k */
1233 "Wrong variant type for 'TargetSpecialFolder' property!\n");
1234 return E_INVALIDARG;
1237 if (!lstrcmpW(pszPropName, wszResolveLinkFlags))
1239 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'ResolveLinkFlags' property!\n");
1240 return E_INVALIDARG;
1243 if (!lstrcmpW(pszPropName, wszTarget)) {
1244 WCHAR wszPath[MAX_PATH];
1247 ok(V_VT(pVar) == VT_BSTR ||
1248 broken(V_VT(pVar) == VT_EMPTY), /* Win2k */
1249 "Wrong variant type for 'Target' property!\n");
1250 if (V_VT(pVar) != VT_BSTR) return E_INVALIDARG;
1252 result = pSHGetSpecialFolderPathW(NULL, wszPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1253 ok(result, "SHGetSpecialFolderPathW(DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1254 if (!result) return E_INVALIDARG;
1256 V_BSTR(pVar) = SysAllocString(wszPath);
1260 if (!lstrcmpW(pszPropName, wszAttributes)) {
1261 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'Attributes' property!\n");
1262 if (V_VT(pVar) != VT_UI4) return E_INVALIDARG;
1263 V_UI4(pVar) = SFGAO_FOLDER|SFGAO_HASSUBFOLDER|SFGAO_FILESYSANCESTOR|
1264 SFGAO_CANRENAME|SFGAO_FILESYSTEM;
1268 if (!lstrcmpW(pszPropName, wszTargetKnownFolder)) {
1269 ok(V_VT(pVar) == VT_BSTR, "Wrong variant type for 'TargetKnownFolder' property!\n");
1271 return E_INVALIDARG;
1274 if (!lstrcmpW(pszPropName, wszCLSID)) {
1275 ok(V_VT(pVar) == VT_EMPTY, "Wrong variant type for 'CLSID' property!\n");
1277 return E_INVALIDARG;
1280 ok(FALSE, "PropertyBag was asked for unknown property %s (vt=%d)!\n", wine_dbgstr_w(pszPropName), V_VT(pVar));
1281 return E_INVALIDARG;
1284 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Write(IPropertyBag *iface, LPCOLESTR pszPropName,
1287 ok(FALSE, "Unexpected call to IPropertyBag_Write\n");
1291 static const IPropertyBagVtbl InitPropertyBag_IPropertyBagVtbl = {
1292 InitPropertyBag_IPropertyBag_QueryInterface,
1293 InitPropertyBag_IPropertyBag_AddRef,
1294 InitPropertyBag_IPropertyBag_Release,
1295 InitPropertyBag_IPropertyBag_Read,
1296 InitPropertyBag_IPropertyBag_Write
1299 static struct IPropertyBag InitPropertyBag = {
1300 &InitPropertyBag_IPropertyBagVtbl
1303 static void test_FolderShortcut(void) {
1304 IPersistPropertyBag *pPersistPropertyBag;
1305 IShellFolder *pShellFolder, *pDesktopFolder;
1306 IPersistFolder3 *pPersistFolder3;
1309 WCHAR wszDesktopPath[MAX_PATH], wszBuffer[MAX_PATH];
1312 LPITEMIDLIST pidlCurrentFolder, pidlWineTestFolder, pidlSubFolder;
1314 WCHAR wszWineTestFolder[] = {
1315 ':',':','{','9','B','3','5','2','E','B','F','-','2','7','6','5','-','4','5','C','1','-',
1316 'B','4','C','6','-','8','5','C','C','7','F','7','A','B','C','6','4','}',0 };
1317 WCHAR wszShellExtKey[] = { 'S','o','f','t','w','a','r','e','\\',
1318 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
1319 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1320 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
1321 'N','a','m','e','S','p','a','c','e','\\',
1322 '{','9','b','3','5','2','e','b','f','-','2','7','6','5','-','4','5','c','1','-',
1323 'b','4','c','6','-','8','5','c','c','7','f','7','a','b','c','6','4','}',0 };
1325 WCHAR wszSomeSubFolder[] = { 'S','u','b','F','o','l','d','e','r', 0};
1326 static const GUID CLSID_UnixDosFolder =
1327 {0x9d20aae8, 0x0625, 0x44b0, {0x9c, 0xa7, 0x71, 0x88, 0x9c, 0x22, 0x54, 0xd9}};
1329 if (!pSHGetSpecialFolderPathW || !pStrRetToBufW) {
1330 win_skip("SHGetSpecialFolderPathW and/or StrRetToBufW are not available\n");
1334 if (!pSHGetFolderPathAndSubDirA)
1336 win_skip("FolderShortcut test doesn't work on Win2k\n");
1340 /* These tests basically show, that CLSID_FolderShortcuts are initialized
1341 * via their IPersistPropertyBag interface. And that the target folder
1342 * is taken from the IPropertyBag's 'Target' property.
1344 hr = CoCreateInstance(&CLSID_FolderShortcut, NULL, CLSCTX_INPROC_SERVER,
1345 &IID_IPersistPropertyBag, (LPVOID*)&pPersistPropertyBag);
1346 if (hr == REGDB_E_CLASSNOTREG) {
1347 win_skip("CLSID_FolderShortcut is not implemented\n");
1350 ok (hr == S_OK, "CoCreateInstance failed! hr = 0x%08x\n", hr);
1351 if (hr != S_OK) return;
1353 hr = IPersistPropertyBag_Load(pPersistPropertyBag, &InitPropertyBag, NULL);
1354 ok(hr == S_OK, "IPersistPropertyBag_Load failed! hr = %08x\n", hr);
1356 IPersistPropertyBag_Release(pPersistPropertyBag);
1360 hr = IPersistPropertyBag_QueryInterface(pPersistPropertyBag, &IID_IShellFolder,
1361 (LPVOID*)&pShellFolder);
1362 IPersistPropertyBag_Release(pPersistPropertyBag);
1363 ok(hr == S_OK, "IPersistPropertyBag_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1364 if (hr != S_OK) return;
1366 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1367 ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1369 IShellFolder_Release(pShellFolder);
1373 result = pSHGetSpecialFolderPathW(NULL, wszDesktopPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1374 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1375 if (!result) return;
1377 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1378 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1380 hr = IShellFolder_QueryInterface(pShellFolder, &IID_IPersistFolder3, (LPVOID*)&pPersistFolder3);
1381 IShellFolder_Release(pShellFolder);
1382 ok(hr == S_OK, "IShellFolder_QueryInterface(IID_IPersistFolder3 failed! hr = 0x%08x\n", hr);
1383 if (hr != S_OK) return;
1385 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1386 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1387 ok(IsEqualCLSID(&clsid, &CLSID_FolderShortcut), "Unexpected CLSID!\n");
1389 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1390 todo_wine ok(hr == S_FALSE, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1391 ok(!pidlCurrentFolder, "IPersistFolder3_GetCurFolder should return a NULL pidl!\n");
1393 /* For FolderShortcut objects, the Initialize method initialized the folder's position in the
1394 * shell namespace. The target folder, read from the property bag above, remains untouched.
1395 * The following tests show this: The itemidlist for some imaginary shellfolder object
1396 * is created and the FolderShortcut is initialized with it. GetCurFolder now returns this
1397 * itemidlist, but GetDisplayNameOf still returns the path from above.
1399 hr = SHGetDesktopFolder(&pDesktopFolder);
1400 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1401 if (hr != S_OK) return;
1403 /* Temporarily register WineTestFolder as a shell namespace extension at the Desktop.
1404 * Otherwise ParseDisplayName fails on WinXP with E_INVALIDARG */
1405 RegCreateKeyW(HKEY_CURRENT_USER, wszShellExtKey, &hShellExtKey);
1406 RegCloseKey(hShellExtKey);
1407 hr = IShellFolder_ParseDisplayName(pDesktopFolder, NULL, NULL, wszWineTestFolder, NULL,
1408 &pidlWineTestFolder, NULL);
1409 RegDeleteKeyW(HKEY_CURRENT_USER, wszShellExtKey);
1410 IShellFolder_Release(pDesktopFolder);
1411 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1412 if (hr != S_OK) return;
1414 hr = IPersistFolder3_Initialize(pPersistFolder3, pidlWineTestFolder);
1415 ok (hr == S_OK, "IPersistFolder3::Initialize failed! hr = %08x\n", hr);
1417 IPersistFolder3_Release(pPersistFolder3);
1418 pILFree(pidlWineTestFolder);
1422 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1423 ok(hr == S_OK, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1424 ok(pILIsEqual(pidlCurrentFolder, pidlWineTestFolder),
1425 "IPersistFolder3_GetCurFolder should return pidlWineTestFolder!\n");
1426 pILFree(pidlCurrentFolder);
1427 pILFree(pidlWineTestFolder);
1429 hr = IPersistFolder3_QueryInterface(pPersistFolder3, &IID_IShellFolder, (LPVOID*)&pShellFolder);
1430 IPersistFolder3_Release(pPersistFolder3);
1431 ok(hr == S_OK, "IPersistFolder3_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1432 if (hr != S_OK) return;
1434 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1435 ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1437 IShellFolder_Release(pShellFolder);
1441 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1442 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1444 /* Next few lines are meant to show that children of FolderShortcuts are not FolderShortcuts,
1445 * but ShellFSFolders. */
1446 myPathAddBackslashW(wszDesktopPath);
1447 lstrcatW(wszDesktopPath, wszSomeSubFolder);
1448 if (!CreateDirectoryW(wszDesktopPath, NULL)) {
1449 IShellFolder_Release(pShellFolder);
1453 hr = IShellFolder_ParseDisplayName(pShellFolder, NULL, NULL, wszSomeSubFolder, NULL,
1454 &pidlSubFolder, NULL);
1455 RemoveDirectoryW(wszDesktopPath);
1456 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1458 IShellFolder_Release(pShellFolder);
1462 hr = IShellFolder_BindToObject(pShellFolder, pidlSubFolder, NULL, &IID_IPersistFolder3,
1463 (LPVOID*)&pPersistFolder3);
1464 IShellFolder_Release(pShellFolder);
1465 pILFree(pidlSubFolder);
1466 ok (hr == S_OK, "IShellFolder::BindToObject failed! hr = %08x\n", hr);
1470 /* On windows, we expect CLSID_ShellFSFolder. On wine we relax this constraint
1471 * a little bit and also allow CLSID_UnixDosFolder. */
1472 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1473 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1474 ok(IsEqualCLSID(&clsid, &CLSID_ShellFSFolder) || IsEqualCLSID(&clsid, &CLSID_UnixDosFolder),
1475 "IPersistFolder3::GetClassID returned unexpected CLSID!\n");
1477 IPersistFolder3_Release(pPersistFolder3);
1480 #include "pshpack1.h"
1481 struct FileStructA {
1485 WORD uFileDate; /* In our current implementation this is */
1486 WORD uFileTime; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastWriteTime) */
1491 struct FileStructW {
1492 WORD cbLen; /* Length of this element. */
1493 BYTE abFooBar1[6]; /* Beyond any recognition. */
1494 WORD uDate; /* FileTimeToDosDate(WIN32_FIND_DATA->ftCreationTime)? */
1495 WORD uTime; /* (this is currently speculation) */
1496 WORD uDate2; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastAccessTime)? */
1497 WORD uTime2; /* (this is currently speculation) */
1498 BYTE abFooBar2[4]; /* Beyond any recognition. */
1499 WCHAR wszName[1]; /* The long filename in unicode. */
1500 /* Just for documentation: Right after the unicode string: */
1501 WORD cbOffset; /* FileStructW's offset from the beginning of the SHITMEID.
1502 * SHITEMID->cb == uOffset + cbLen */
1504 #include "poppack.h"
1506 static void test_ITEMIDLIST_format(void) {
1507 WCHAR wszPersonal[MAX_PATH];
1508 LPSHELLFOLDER psfDesktop, psfPersonal;
1509 LPITEMIDLIST pidlPersonal, pidlFile;
1513 WCHAR wszFile[3][17] = { { 'e','v','e','n','_',0 }, { 'o','d','d','_',0 },
1514 { 'l','o','n','g','e','r','_','t','h','a','n','.','8','_','3',0 } };
1517 if (!pSHGetSpecialFolderPathW) return;
1519 bResult = pSHGetSpecialFolderPathW(NULL, wszPersonal, CSIDL_PERSONAL, FALSE);
1520 ok(bResult, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1521 if (!bResult) return;
1523 SetLastError(0xdeadbeef);
1524 bResult = SetCurrentDirectoryW(wszPersonal);
1525 if (!bResult && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
1526 win_skip("Most W-calls are not implemented\n");
1529 ok(bResult, "SetCurrentDirectory failed! Last error: %u\n", GetLastError());
1530 if (!bResult) return;
1532 hr = SHGetDesktopFolder(&psfDesktop);
1533 ok(hr == S_OK, "SHGetDesktopFolder failed! hr: %08x\n", hr);
1534 if (hr != S_OK) return;
1536 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszPersonal, NULL, &pidlPersonal, NULL);
1537 ok(hr == S_OK, "psfDesktop->ParseDisplayName failed! hr = %08x\n", hr);
1539 IShellFolder_Release(psfDesktop);
1543 hr = IShellFolder_BindToObject(psfDesktop, pidlPersonal, NULL, &IID_IShellFolder,
1544 (LPVOID*)&psfPersonal);
1545 IShellFolder_Release(psfDesktop);
1546 pILFree(pidlPersonal);
1547 ok(hr == S_OK, "psfDesktop->BindToObject failed! hr = %08x\n", hr);
1548 if (hr != S_OK) return;
1550 for (i=0; i<3; i++) {
1551 CHAR szFile[MAX_PATH];
1552 struct FileStructA *pFileStructA;
1555 WideCharToMultiByte(CP_ACP, 0, wszFile[i], -1, szFile, MAX_PATH, NULL, NULL);
1557 hFile = CreateFileW(wszFile[i], GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_FLAG_WRITE_THROUGH, NULL);
1558 ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed! (%u)\n", GetLastError());
1559 if (hFile == INVALID_HANDLE_VALUE) {
1560 IShellFolder_Release(psfPersonal);
1565 hr = IShellFolder_ParseDisplayName(psfPersonal, NULL, NULL, wszFile[i], NULL, &pidlFile, NULL);
1566 DeleteFileW(wszFile[i]);
1567 ok(hr == S_OK, "psfPersonal->ParseDisplayName failed! hr: %08x\n", hr);
1569 IShellFolder_Release(psfPersonal);
1573 pFileStructA = (struct FileStructA *)pidlFile->mkid.abID;
1574 ok(pFileStructA->type == 0x32, "PIDLTYPE should be 0x32!\n");
1575 ok(pFileStructA->dummy == 0x00, "Dummy Byte should be 0x00!\n");
1576 ok(pFileStructA->dwFileSize == 0, "Filesize should be zero!\n");
1578 if (i < 2) /* First two file names are already in valid 8.3 format */
1579 ok(!strcmp(szFile, (CHAR*)&pidlFile->mkid.abID[12]), "Wrong file name!\n");
1581 /* WinXP stores a derived 8.3 dos name (LONGER~1.8_3) here. We probably
1582 * can't implement this correctly, since unix filesystems don't support
1583 * this nasty short/long filename stuff. So we'll probably stay with our
1584 * current habbit of storing the long filename here, which seems to work
1587 ok(pidlFile->mkid.abID[18] == '~' ||
1588 broken(pidlFile->mkid.abID[34] == '~'), /* Win2k */
1589 "Should be derived 8.3 name!\n");
1591 if (i == 0) /* First file name has an even number of chars. No need for alignment. */
1592 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] != '\0' ||
1593 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1), /* Win2k */
1594 "Alignment byte, where there shouldn't be!\n");
1596 if (i == 1) /* Second file name has an uneven number of chars => alignment byte */
1597 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] == '\0',
1598 "There should be an alignment byte, but isn't!\n");
1600 /* The offset of the FileStructW member is stored as a WORD at the end of the pidl. */
1601 cbOffset = *(WORD*)(((LPBYTE)pidlFile)+pidlFile->mkid.cb-sizeof(WORD));
1602 ok ((cbOffset >= sizeof(struct FileStructA) &&
1603 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW)) ||
1604 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1) || /* Win2k on short names */
1605 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 12 + 1), /* Win2k on long names */
1606 "Wrong offset value (%d) stored at the end of the PIDL\n", cbOffset);
1608 if (cbOffset >= sizeof(struct FileStructA) &&
1609 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW))
1611 struct FileStructW *pFileStructW = (struct FileStructW *)(((LPBYTE)pidlFile)+cbOffset);
1613 ok(pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen,
1614 "FileStructW's offset and length should add up to the PIDL's length!\n");
1616 if (pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen) {
1617 /* Since we just created the file, time of creation,
1618 * time of last access and time of last write access just be the same.
1619 * These tests seem to fail sometimes (on WinXP), if the test is run again shortly
1620 * after the first run. I do remember something with NTFS keeping the creation time
1621 * if a file is deleted and then created again within a couple of seconds or so.
1622 * Might be the reason. */
1623 ok (pFileStructA->uFileDate == pFileStructW->uDate &&
1624 pFileStructA->uFileTime == pFileStructW->uTime,
1625 "Last write time should match creation time!\n");
1627 /* On FAT filesystems the last access time is midnight
1628 local time, so the values of uDate2 and uTime2 will
1629 depend on the local timezone. If the times are exactly
1630 equal then the dates should be identical for both FAT
1631 and NTFS as no timezone is more than 1 day away from UTC.
1633 if (pFileStructA->uFileTime == pFileStructW->uTime2)
1635 ok (pFileStructA->uFileDate == pFileStructW->uDate2,
1636 "Last write date and time should match last access date and time!\n");
1640 /* Filesystem may be FAT. Check date within 1 day
1641 and seconds are zero. */
1642 trace ("Filesystem may be FAT. Performing less strict atime test.\n");
1643 ok ((pFileStructW->uTime2 & 0x1F) == 0,
1644 "Last access time on FAT filesystems should have zero seconds.\n");
1645 /* TODO: Perform check for date being within one day.*/
1648 ok (!lstrcmpW(wszFile[i], pFileStructW->wszName) ||
1649 !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 22)) || /* Vista */
1650 !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 26)), /* Win7 */
1651 "The filename should be stored in unicode at this position!\n");
1658 IShellFolder_Release(psfPersonal);
1661 static void test_SHGetFolderPathAndSubDirA(void)
1667 static char wine[] = "wine";
1668 static char winetemp[] = "wine\\temp";
1669 static char appdata[MAX_PATH];
1670 static char testpath[MAX_PATH];
1671 static char toolongpath[MAX_PATH+1];
1673 if(!pSHGetFolderPathAndSubDirA)
1675 win_skip("SHGetFolderPathAndSubDirA not present!\n");
1679 if(!pSHGetFolderPathA) {
1680 win_skip("SHGetFolderPathA not present!\n");
1683 if(FAILED(pSHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdata)))
1685 win_skip("SHGetFolderPathA failed for CSIDL_LOCAL_APPDATA!\n");
1689 sprintf(testpath, "%s\\%s", appdata, winetemp);
1690 delret = RemoveDirectoryA(testpath);
1691 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) ) {
1692 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1696 sprintf(testpath, "%s\\%s", appdata, wine);
1697 delret = RemoveDirectoryA(testpath);
1698 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) && (ERROR_FILE_NOT_FOUND != GetLastError())) {
1699 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1703 /* test invalid second parameter */
1704 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | 0xff, NULL, SHGFP_TYPE_CURRENT, wine, testpath);
1705 ok(E_INVALIDARG == ret, "expected E_INVALIDARG, got %x\n", ret);
1707 /* test fourth parameter */
1708 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, 2, winetemp, testpath);
1710 case S_OK: /* winvista */
1711 ok(!strncmp(appdata, testpath, strlen(appdata)),
1712 "expected %s to start with %s\n", testpath, appdata);
1713 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1714 "expected %s to end with %s\n", testpath, winetemp);
1716 case E_INVALIDARG: /* winxp, win2k3 */
1719 ok(0, "expected S_OK or E_INVALIDARG, got %x\n", ret);
1722 /* test fifth parameter */
1724 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, NULL, testpath);
1725 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1726 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1729 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "", testpath);
1730 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1731 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1734 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "\\", testpath);
1735 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1736 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1738 for(i=0; i< MAX_PATH; i++)
1739 toolongpath[i] = '0' + i % 10;
1740 toolongpath[MAX_PATH] = '\0';
1741 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, toolongpath, testpath);
1742 ok(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) == ret,
1743 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), ret);
1746 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wine, NULL);
1747 ok((S_OK == ret) || (E_INVALIDARG == ret), "expected S_OK or E_INVALIDARG, got %x\n", ret);
1749 /* test a not existing path */
1751 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
1752 ok(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == ret,
1753 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), ret);
1755 /* create a directory inside a not existing directory */
1757 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_CREATE | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
1758 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1759 ok(!strncmp(appdata, testpath, strlen(appdata)),
1760 "expected %s to start with %s\n", testpath, appdata);
1761 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1762 "expected %s to end with %s\n", testpath, winetemp);
1763 dwret = GetFileAttributes(testpath);
1764 ok(FILE_ATTRIBUTE_DIRECTORY | dwret, "expected %x to contain FILE_ATTRIBUTE_DIRECTORY\n", dwret);
1767 sprintf(testpath, "%s\\%s", appdata, winetemp);
1768 RemoveDirectoryA(testpath);
1769 sprintf(testpath, "%s\\%s", appdata, wine);
1770 RemoveDirectoryA(testpath);
1773 static void test_LocalizedNames(void)
1775 static char cCurrDirA[MAX_PATH];
1776 WCHAR cCurrDirW[MAX_PATH], tempbufW[25];
1777 IShellFolder *IDesktopFolder, *testIShellFolder;
1778 ITEMIDLIST *newPIDL;
1781 static char resourcefile[MAX_PATH];
1786 static const char desktopini_contents1[] =
1787 "[.ShellClassInfo]\r\n"
1788 "LocalizedResourceName=@";
1789 static const char desktopini_contents2[] =
1791 static WCHAR foldernameW[] = {'t','e','s','t','f','o','l','d','e','r',0};
1792 static const WCHAR folderdisplayW[] = {'F','o','l','d','e','r',' ','N','a','m','e',' ','R','e','s','o','u','r','c','e',0};
1794 /* create folder with desktop.ini and localized name in GetModuleFileNameA(NULL) */
1795 CreateDirectoryA(".\\testfolder", NULL);
1797 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")|FILE_ATTRIBUTE_SYSTEM);
1799 GetModuleFileNameA(NULL, resourcefile, MAX_PATH);
1801 file = CreateFileA(".\\testfolder\\desktop.ini", GENERIC_WRITE, 0, NULL,
1802 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1803 ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %i\n", GetLastError());
1804 ok(WriteFile(file, desktopini_contents1, strlen(desktopini_contents1), &res, NULL) &&
1805 WriteFile(file, resourcefile, strlen(resourcefile), &res, NULL) &&
1806 WriteFile(file, desktopini_contents2, strlen(desktopini_contents2), &res, NULL),
1807 "WriteFile failed %i\n", GetLastError());
1810 /* get IShellFolder for parent */
1811 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1812 len = lstrlenA(cCurrDirA);
1815 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_LocalizedNames\n");
1818 if(cCurrDirA[len-1] == '\\')
1819 cCurrDirA[len-1] = 0;
1821 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1823 hr = SHGetDesktopFolder(&IDesktopFolder);
1824 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1826 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1827 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1829 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1830 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1832 IMalloc_Free(ppM, newPIDL);
1834 /* windows reads the display name from the resource */
1835 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, foldernameW, NULL, &newPIDL, 0);
1836 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1838 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER, &strret);
1839 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1841 if (hr == S_OK && pStrRetToBufW)
1843 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1844 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1846 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
1847 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
1848 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1851 /* editing name is also read from the resource */
1852 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FOREDITING, &strret);
1853 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1855 if (hr == S_OK && pStrRetToBufW)
1857 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1858 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1860 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
1861 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
1862 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1865 /* parsing name is unchanged */
1866 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FORPARSING, &strret);
1867 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1869 if (hr == S_OK && pStrRetToBufW)
1871 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1872 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1873 ok (!lstrcmpiW(tempbufW, foldernameW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1876 IShellFolder_Release(IDesktopFolder);
1877 IShellFolder_Release(testIShellFolder);
1879 IMalloc_Free(ppM, newPIDL);
1882 DeleteFileA(".\\testfolder\\desktop.ini");
1883 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")&~FILE_ATTRIBUTE_SYSTEM);
1884 RemoveDirectoryA(".\\testfolder");
1887 static void test_SHCreateShellItem(void)
1889 IShellItem *shellitem, *shellitem2;
1890 IPersistIDList *persistidl;
1891 LPITEMIDLIST pidl_cwd=NULL, pidl_testfile, pidl_abstestfile, pidl_test;
1893 char curdirA[MAX_PATH];
1894 WCHAR curdirW[MAX_PATH];
1895 WCHAR fnbufW[MAX_PATH];
1896 IShellFolder *desktopfolder=NULL, *currentfolder=NULL;
1897 static WCHAR testfileW[] = {'t','e','s','t','f','i','l','e',0};
1899 GetCurrentDirectoryA(MAX_PATH, curdirA);
1901 if (!pSHCreateShellItem)
1903 win_skip("SHCreateShellItem isn't available\n");
1907 if (!lstrlenA(curdirA))
1909 win_skip("GetCurrentDirectoryA returned empty string, skipping test_SHCreateShellItem\n");
1913 MultiByteToWideChar(CP_ACP, 0, curdirA, -1, curdirW, MAX_PATH);
1915 ret = SHGetDesktopFolder(&desktopfolder);
1916 ok(SUCCEEDED(ret), "SHGetShellFolder returned %x\n", ret);
1918 ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
1919 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
1921 ret = IShellFolder_BindToObject(desktopfolder, pidl_cwd, NULL, &IID_IShellFolder, (void**)¤tfolder);
1922 ok(SUCCEEDED(ret), "BindToObject returned %x\n", ret);
1924 CreateTestFile(".\\testfile");
1926 ret = IShellFolder_ParseDisplayName(currentfolder, NULL, NULL, testfileW, NULL, &pidl_testfile, NULL);
1927 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
1929 pidl_abstestfile = pILCombine(pidl_cwd, pidl_testfile);
1931 ret = pSHCreateShellItem(NULL, NULL, NULL, &shellitem);
1932 ok(ret == E_INVALIDARG, "SHCreateShellItem returned %x\n", ret);
1934 if (0) /* crashes on Windows XP */
1936 pSHCreateShellItem(NULL, NULL, pidl_cwd, NULL);
1937 pSHCreateShellItem(pidl_cwd, NULL, NULL, &shellitem);
1938 pSHCreateShellItem(NULL, currentfolder, NULL, &shellitem);
1939 pSHCreateShellItem(pidl_cwd, currentfolder, NULL, &shellitem);
1942 ret = pSHCreateShellItem(NULL, NULL, pidl_cwd, &shellitem);
1943 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
1946 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
1947 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1950 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1951 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1954 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
1957 IPersistIDList_Release(persistidl);
1959 IShellItem_Release(shellitem);
1962 ret = pSHCreateShellItem(pidl_cwd, NULL, pidl_testfile, &shellitem);
1963 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
1966 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
1967 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1970 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1971 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1974 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
1977 IPersistIDList_Release(persistidl);
1980 ret = IShellItem_GetParent(shellitem, &shellitem2);
1981 ok(SUCCEEDED(ret), "GetParent returned %x\n", ret);
1984 ret = IShellItem_QueryInterface(shellitem2, &IID_IPersistIDList, (void**)&persistidl);
1985 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1988 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1989 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1992 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
1995 IPersistIDList_Release(persistidl);
1997 IShellItem_Release(shellitem2);
2000 IShellItem_Release(shellitem);
2003 ret = pSHCreateShellItem(NULL, currentfolder, pidl_testfile, &shellitem);
2004 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2007 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2008 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2011 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2012 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2015 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2018 IPersistIDList_Release(persistidl);
2020 IShellItem_Release(shellitem);
2023 /* if a parent pidl and shellfolder are specified, the shellfolder is ignored */
2024 ret = pSHCreateShellItem(pidl_cwd, desktopfolder, pidl_testfile, &shellitem);
2025 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2028 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2029 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2032 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2033 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2036 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2039 IPersistIDList_Release(persistidl);
2041 IShellItem_Release(shellitem);
2044 ret = pSHCreateShellItem(NULL, desktopfolder, pidl_testfile, &shellitem);
2045 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2048 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2049 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2052 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2053 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2056 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2059 IPersistIDList_Release(persistidl);
2061 IShellItem_Release(shellitem);
2064 /* SHCreateItemFromParsingName */
2065 if(pSHCreateItemFromParsingName)
2069 /* Crashes under windows 7 */
2070 ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, NULL);
2073 shellitem = (void*)0xdeadbeef;
2074 ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, (void**)&shellitem);
2075 ok(ret == E_INVALIDARG, "SHCreateItemFromParsingName returned %x\n", ret);
2076 ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2078 ret = pSHCreateItemFromParsingName(testfileW, NULL, &IID_IShellItem, (void**)&shellitem);
2079 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
2080 "SHCreateItemFromParsingName returned %x\n", ret);
2081 if(SUCCEEDED(ret)) IShellItem_Release(shellitem);
2083 lstrcpyW(fnbufW, curdirW);
2084 myPathAddBackslashW(fnbufW);
2085 lstrcatW(fnbufW, testfileW);
2087 ret = pSHCreateItemFromParsingName(fnbufW, NULL, &IID_IShellItem, (void**)&shellitem);
2088 ok(ret == S_OK, "SHCreateItemFromParsingName returned %x\n", ret);
2092 ret = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &tmp_fname);
2093 ok(ret == S_OK, "GetDisplayName returned %x\n", ret);
2096 ok(!lstrcmpW(fnbufW, tmp_fname), "strings not equal\n");
2097 CoTaskMemFree(tmp_fname);
2099 IShellItem_Release(shellitem);
2103 win_skip("No SHCreateItemFromParsingName\n");
2106 /* SHCreateItemFromIDList */
2107 if(pSHCreateItemFromIDList)
2111 /* Crashes under win7 */
2112 ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, NULL);
2115 ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, (void**)&shellitem);
2116 ok(ret == E_INVALIDARG, "SHCreateItemFromIDList returned %x\n", ret);
2118 ret = pSHCreateItemFromIDList(pidl_cwd, &IID_IShellItem, (void**)&shellitem);
2119 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2122 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2123 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2126 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2127 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2130 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2133 IPersistIDList_Release(persistidl);
2135 IShellItem_Release(shellitem);
2138 ret = pSHCreateItemFromIDList(pidl_testfile, &IID_IShellItem, (void**)&shellitem);
2139 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2142 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2143 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2146 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2147 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2150 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2153 IPersistIDList_Release(persistidl);
2155 IShellItem_Release(shellitem);
2159 win_skip("No SHCreateItemFromIDList\n");
2161 DeleteFileA(".\\testfile");
2162 pILFree(pidl_abstestfile);
2163 pILFree(pidl_testfile);
2165 IShellFolder_Release(currentfolder);
2166 IShellFolder_Release(desktopfolder);
2169 static void test_SHGetNameFromIDList(void)
2171 IShellItem *shellitem;
2176 static const DWORD flags[] = {
2177 SIGDN_NORMALDISPLAY, SIGDN_PARENTRELATIVEPARSING,
2178 SIGDN_DESKTOPABSOLUTEPARSING,SIGDN_PARENTRELATIVEEDITING,
2179 SIGDN_DESKTOPABSOLUTEEDITING, /*SIGDN_FILESYSPATH, SIGDN_URL, */
2180 SIGDN_PARENTRELATIVEFORADDRESSBAR,SIGDN_PARENTRELATIVE, -1234};
2182 if(!pSHGetNameFromIDList)
2184 win_skip("SHGetNameFromIDList missing.\n");
2188 /* These should be available on any platform that passed the above test. */
2189 ok(pSHCreateShellItem != NULL, "SHCreateShellItem missing.\n");
2190 ok(pSHBindToParent != NULL, "SHBindToParent missing.\n");
2191 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
2192 ok(pStrRetToBufW != NULL, "StrRetToBufW missing.\n");
2196 /* Crashes under win7 */
2197 hres = pSHGetNameFromIDList(NULL, 0, NULL);
2200 hres = pSHGetNameFromIDList(NULL, 0, &name_string);
2201 ok(hres == E_INVALIDARG, "Got 0x%08x\n", hres);
2203 /* Test the desktop */
2204 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
2205 ok(hres == S_OK, "Got 0x%08x\n", hres);
2206 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2207 ok(hres == S_OK, "Got 0x%08x\n", hres);
2210 WCHAR *nameSI, *nameSH;
2211 WCHAR buf[MAX_PATH];
2212 HRESULT hrSI, hrSH, hrSF;
2217 SHGetDesktopFolder(&psf);
2218 for(i = 0; flags[i] != -1234; i++)
2220 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2221 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2222 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2223 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2224 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2225 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2227 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2228 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2232 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2234 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2236 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2238 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2239 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2241 IShellFolder_Release(psf);
2243 if(pSHGetPathFromIDListW){
2244 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2245 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2246 res = pSHGetPathFromIDListW(pidl, buf);
2247 ok(res == TRUE, "Got %d\n", res);
2248 if(SUCCEEDED(hrSI) && res)
2249 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2250 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2252 win_skip("pSHGetPathFromIDListW not available\n");
2254 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2255 todo_wine ok(hres == S_OK, "Got 0x%08x\n", hres);
2256 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2258 IShellItem_Release(shellitem);
2262 /* Test the control panel */
2263 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_CONTROLS, &pidl);
2264 ok(hres == S_OK, "Got 0x%08x\n", hres);
2265 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2266 ok(hres == S_OK, "Got 0x%08x\n", hres);
2269 WCHAR *nameSI, *nameSH;
2270 WCHAR buf[MAX_PATH];
2271 HRESULT hrSI, hrSH, hrSF;
2276 SHGetDesktopFolder(&psf);
2277 for(i = 0; flags[i] != -1234; i++)
2279 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2280 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2281 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2282 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2283 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2284 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2286 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2287 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2291 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2293 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2295 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2297 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2298 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2300 IShellFolder_Release(psf);
2302 if(pSHGetPathFromIDListW){
2303 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2304 ok(hrSI == E_INVALIDARG, "Got 0x%08x\n", hrSI);
2305 res = pSHGetPathFromIDListW(pidl, buf);
2306 ok(res == FALSE, "Got %d\n", res);
2307 if(SUCCEEDED(hrSI) && res)
2308 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2309 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2311 win_skip("pSHGetPathFromIDListW not available\n");
2313 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2314 todo_wine ok(hres == E_NOTIMPL /* Win7 */ || hres == S_OK /* Vista */,
2315 "Got 0x%08x\n", hres);
2316 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2318 IShellItem_Release(shellitem);
2323 static void test_SHGetItemFromDataObject(void)
2325 IShellFolder *psfdesktop;
2330 if(!pSHGetItemFromDataObject)
2332 win_skip("No SHGetItemFromDataObject.\n");
2338 /* Crashes under win7 */
2339 hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, NULL);
2342 hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, (void**)&psv);
2343 ok(hres == E_INVALIDARG, "got 0x%08x\n", hres);
2345 SHGetDesktopFolder(&psfdesktop);
2347 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
2348 ok(hres == S_OK, "got 0x%08x\n", hres);
2355 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
2356 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
2357 ok(hres == S_OK, "got 0x%08x\n", hres);
2360 LPITEMIDLIST apidl[5];
2363 for(count = 0; count < 5; count++)
2364 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
2369 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
2370 &IID_IDataObject, NULL, (void**)&pdo);
2371 ok(hres == S_OK, "got 0x%08x\n", hres);
2374 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2375 ok(hres == S_OK, "got 0x%08x\n", hres);
2376 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2377 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2378 ok(hres == S_OK, "got 0x%08x\n", hres);
2379 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2380 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2381 ok(hres == S_OK, "got 0x%08x\n", hres);
2382 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2383 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2384 ok(hres == S_OK, "got 0x%08x\n", hres);
2385 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2386 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2387 ok(hres == S_OK, "got 0x%08x\n", hres);
2388 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2390 IDataObject_Release(pdo);
2394 skip("No file(s) found - skipping single-file test.\n");
2398 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
2399 &IID_IDataObject, NULL, (void**)&pdo);
2400 ok(hres == S_OK, "got 0x%08x\n", hres);
2403 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2404 ok(hres == S_OK, "got 0x%08x\n", hres);
2405 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2406 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2407 ok(hres == S_OK, "got 0x%08x\n", hres);
2408 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2409 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2410 ok(hres == S_OK, "got 0x%08x\n", hres);
2411 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2412 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2413 ok(hres == S_OK, "got 0x%08x\n", hres);
2414 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2415 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2416 ok(hres == E_FAIL, "got 0x%08x\n", hres);
2417 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2418 IDataObject_Release(pdo);
2422 skip("zero or one file found - skipping multi-file test.\n");
2424 for(i = 0; i < count; i++)
2427 IEnumIDList_Release(peidl);
2430 IShellView_Release(psv);
2433 IShellFolder_Release(psfdesktop);
2436 static void test_ShellItemCompare(void)
2438 IShellItem *psi[9]; /* a\a, a\b, a\c, b\a, .. */
2439 IShellItem *psi_a, *psi_b, *psi_c;
2440 IShellFolder *psf_desktop, *psf_current;
2441 LPITEMIDLIST pidl_cwd;
2442 WCHAR curdirW[MAX_PATH];
2445 static const WCHAR filesW[][9] = {
2446 {'a','\\','a',0}, {'a','\\','b',0}, {'a','\\','c',0},
2447 {'b','\\','a',0}, {'b','\\','b',0}, {'b','\\','c',0},
2448 {'c','\\','a',0}, {'c','\\','b',0}, {'c','\\','c',0} };
2452 if(!pSHCreateShellItem)
2454 win_skip("SHCreateShellItem missing.\n");
2458 GetCurrentDirectoryW(MAX_PATH, curdirW);
2459 if(!lstrlenW(curdirW))
2461 skip("Failed to get current directory, skipping.\n");
2465 CreateDirectoryA(".\\a", NULL);
2466 CreateDirectoryA(".\\b", NULL);
2467 CreateDirectoryA(".\\c", NULL);
2468 CreateTestFile(".\\a\\a");
2469 CreateTestFile(".\\a\\b");
2470 CreateTestFile(".\\a\\c");
2471 CreateTestFile(".\\b\\a");
2472 CreateTestFile(".\\b\\b");
2473 CreateTestFile(".\\b\\c");
2474 CreateTestFile(".\\c\\a");
2475 CreateTestFile(".\\c\\b");
2476 CreateTestFile(".\\c\\c");
2478 SHGetDesktopFolder(&psf_desktop);
2479 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2480 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2481 hr = IShellFolder_BindToObject(psf_desktop, pidl_cwd, NULL, &IID_IShellFolder, (void**)&psf_current);
2482 ok(SUCCEEDED(hr), "BindToObject returned %x\n", hr);
2483 IShellFolder_Release(psf_desktop);
2485 /* Generate ShellItems for the files */
2486 ZeroMemory(&psi, sizeof(IShellItem*)*9);
2488 for(i = 0; i < 9; i++)
2490 LPITEMIDLIST pidl_testfile = NULL;
2492 hr = IShellFolder_ParseDisplayName(psf_current, NULL, NULL, (LPWSTR)filesW[i],
2493 NULL, &pidl_testfile, NULL);
2494 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2497 hr = pSHCreateShellItem(NULL, NULL, pidl_testfile, &psi[i]);
2498 ok(hr == S_OK, "Got 0x%08x\n", hr);
2499 pILFree(pidl_testfile);
2501 if(FAILED(hr)) failed = TRUE;
2505 skip("Failed to create all shellitems. \n");
2509 /* Generate ShellItems for the folders */
2510 psi_a = psi_b = psi_c = NULL;
2511 hr = IShellItem_GetParent(psi[0], &psi_a);
2512 ok(hr == S_OK, "Got 0x%08x\n", hr);
2513 if(FAILED(hr)) failed = TRUE;
2514 hr = IShellItem_GetParent(psi[3], &psi_b);
2515 ok(hr == S_OK, "Got 0x%08x\n", hr);
2516 if(FAILED(hr)) failed = TRUE;
2517 hr = IShellItem_GetParent(psi[6], &psi_c);
2518 ok(hr == S_OK, "Got 0x%08x\n", hr);
2519 if(FAILED(hr)) failed = TRUE;
2523 skip("Failed to create shellitems. \n");
2529 /* Crashes on native (win7, winxp) */
2530 hr = IShellItem_Compare(psi_a, NULL, 0, NULL);
2531 hr = IShellItem_Compare(psi_a, psi_b, 0, NULL);
2532 hr = IShellItem_Compare(psi_a, NULL, 0, &order);
2536 for(i = 0; i < 9; i++)
2538 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_DISPLAY, &order);
2539 ok(hr == S_OK, "Got 0x%08x\n", hr);
2540 ok(order == 0, "Got order %d\n", order);
2541 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_CANONICAL, &order);
2542 ok(hr == S_OK, "Got 0x%08x\n", hr);
2543 ok(order == 0, "Got order %d\n", order);
2544 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_ALLFIELDS, &order);
2545 ok(hr == S_OK, "Got 0x%08x\n", hr);
2546 ok(order == 0, "Got order %d\n", order);
2550 /* a\b:a\a , a\b:a\c, a\b:a\b */
2551 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_DISPLAY, &order);
2552 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2553 ok(order == 1, "Got order %d\n", order);
2554 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_DISPLAY, &order);
2555 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2556 ok(order == -1, "Got order %d\n", order);
2557 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_DISPLAY, &order);
2558 ok(hr == S_OK, "Got 0x%08x\n", hr);
2559 ok(order == 0, "Got order %d\n", order);
2561 /* b\b:a\b, b\b:c\b, b\b:c\b */
2562 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_DISPLAY, &order);
2563 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2564 ok(order == 1, "Got order %d\n", order);
2565 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_DISPLAY, &order);
2566 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2567 ok(order == -1, "Got order %d\n", order);
2568 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_DISPLAY, &order);
2569 ok(hr == S_OK, "Got 0x%08x\n", hr);
2570 ok(order == 0, "Got order %d\n", order);
2572 /* b:a\a, b:a\c, b:a\b */
2573 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_DISPLAY, &order);
2574 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2575 todo_wine ok(order == 1, "Got order %d\n", order);
2576 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_DISPLAY, &order);
2577 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2578 todo_wine ok(order == 1, "Got order %d\n", order);
2579 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_DISPLAY, &order);
2580 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2581 todo_wine ok(order == 1, "Got order %d\n", order);
2583 /* b:c\a, b:c\c, b:c\b */
2584 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_DISPLAY, &order);
2585 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2586 ok(order == -1, "Got order %d\n", order);
2587 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_DISPLAY, &order);
2588 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2589 ok(order == -1, "Got order %d\n", order);
2590 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_DISPLAY, &order);
2591 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2592 ok(order == -1, "Got order %d\n", order);
2594 /* a\b:a\a , a\b:a\c, a\b:a\b */
2595 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_CANONICAL, &order);
2596 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2597 ok(order == 1, "Got order %d\n", order);
2598 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_CANONICAL, &order);
2599 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2600 ok(order == -1, "Got order %d\n", order);
2601 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_CANONICAL, &order);
2602 ok(hr == S_OK, "Got 0x%08x\n", hr);
2603 ok(order == 0, "Got order %d\n", order);
2605 /* b\b:a\b, b\b:c\b, b\b:c\b */
2606 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_CANONICAL, &order);
2607 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2608 ok(order == 1, "Got order %d\n", order);
2609 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_CANONICAL, &order);
2610 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2611 ok(order == -1, "Got order %d\n", order);
2612 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_CANONICAL, &order);
2613 ok(hr == S_OK, "Got 0x%08x\n", hr);
2614 ok(order == 0, "Got order %d\n", order);
2616 /* b:a\a, b:a\c, b:a\b */
2617 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_CANONICAL, &order);
2618 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2619 todo_wine ok(order == 1, "Got order %d\n", order);
2620 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_CANONICAL, &order);
2621 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2622 todo_wine ok(order == 1, "Got order %d\n", order);
2623 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_CANONICAL, &order);
2624 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2625 todo_wine ok(order == 1, "Got order %d\n", order);
2627 /* b:c\a, b:c\c, b:c\b */
2628 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_CANONICAL, &order);
2629 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2630 ok(order == -1, "Got order %d\n", order);
2631 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_CANONICAL, &order);
2632 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2633 ok(order == -1, "Got order %d\n", order);
2634 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_CANONICAL, &order);
2635 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2636 ok(order == -1, "Got order %d\n", order);
2639 IShellFolder_Release(psf_current);
2641 DeleteFileA(".\\a\\a");
2642 DeleteFileA(".\\a\\b");
2643 DeleteFileA(".\\a\\c");
2644 DeleteFileA(".\\b\\a");
2645 DeleteFileA(".\\b\\b");
2646 DeleteFileA(".\\b\\c");
2647 DeleteFileA(".\\c\\a");
2648 DeleteFileA(".\\c\\b");
2649 DeleteFileA(".\\c\\c");
2650 RemoveDirectoryA(".\\a");
2651 RemoveDirectoryA(".\\b");
2652 RemoveDirectoryA(".\\c");
2654 if(psi_a) IShellItem_Release(psi_a);
2655 if(psi_b) IShellItem_Release(psi_b);
2656 if(psi_c) IShellItem_Release(psi_c);
2658 for(i = 0; i < 9; i++)
2659 if(psi[i]) IShellItem_Release(psi[i]);
2662 /**************************************************************/
2663 /* IUnknown implementation for counting QueryInterface calls. */
2665 const IUnknownVtbl *lpVtbl;
2673 static HRESULT WINAPI unk_fnQueryInterface(IUnknown *iunk, REFIID riid, void** punk)
2675 IUnknownImpl *This = (IUnknownImpl*)iunk;
2677 for(i = found = 0; This->ifaces[i].id != NULL; i++)
2679 if(IsEqualIID(This->ifaces[i].id, riid))
2681 This->ifaces[i].count++;
2688 return E_NOINTERFACE;
2691 static ULONG WINAPI unk_fnAddRef(IUnknown *iunk)
2696 static ULONG WINAPI unk_fnRelease(IUnknown *iunk)
2701 const IUnknownVtbl vt_IUnknown = {
2702 unk_fnQueryInterface,
2707 static void test_SHGetIDListFromObject(void)
2709 IUnknownImpl *punkimpl;
2710 IShellFolder *psfdesktop;
2712 LPITEMIDLIST pidl, pidl_desktop;
2715 struct if_count ifaces[] =
2716 { {&IID_IPersistIDList, 0},
2717 {&IID_IPersistFolder2, 0},
2718 {&IID_IDataObject, 0},
2719 {&IID_IParentAndItem, 0},
2720 {&IID_IFolderView, 0},
2723 if(!pSHGetIDListFromObject)
2725 win_skip("SHGetIDListFromObject missing.\n");
2729 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
2733 /* Crashes native */
2734 pSHGetIDListFromObject(NULL, NULL);
2735 pSHGetIDListFromObject((void*)0xDEADBEEF, NULL);
2738 hres = pSHGetIDListFromObject(NULL, &pidl);
2739 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
2741 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
2742 punkimpl->lpVtbl = &vt_IUnknown;
2743 punkimpl->ifaces = ifaces;
2744 punkimpl->unknown = 0;
2746 hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
2747 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
2748 ok(ifaces[0].count, "interface not requested.\n");
2749 ok(ifaces[1].count, "interface not requested.\n");
2750 ok(ifaces[2].count, "interface not requested.\n");
2752 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
2753 "interface not requested.\n");
2754 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
2755 "interface not requested.\n");
2757 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
2758 HeapFree(GetProcessHeap(), 0, punkimpl);
2760 pidl_desktop = NULL;
2761 pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
2762 ok(pidl_desktop != NULL, "Failed to get desktop pidl.\n");
2764 SHGetDesktopFolder(&psfdesktop);
2766 /* Test IShellItem */
2767 if(pSHCreateShellItem)
2769 IShellItem *shellitem;
2770 hres = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
2771 ok(hres == S_OK, "got 0x%08x\n", hres);
2774 hres = pSHGetIDListFromObject((IUnknown*)shellitem, &pidl);
2775 ok(hres == S_OK, "got 0x%08x\n", hres);
2778 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
2781 IShellItem_Release(shellitem);
2785 skip("no SHCreateShellItem.\n");
2787 /* Test IShellFolder */
2788 hres = pSHGetIDListFromObject((IUnknown*)psfdesktop, &pidl);
2789 ok(hres == S_OK, "got 0x%08x\n", hres);
2792 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
2796 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
2797 ok(hres == S_OK, "got 0x%08x\n", hres);
2804 /* Test IFolderView */
2805 hres = pSHGetIDListFromObject((IUnknown*)psv, &pidl);
2806 ok(hres == S_OK, "got 0x%08x\n", hres);
2809 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
2813 /* Test IDataObject */
2814 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
2815 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
2816 ok(hres == S_OK, "got 0x%08x\n", hres);
2819 LPITEMIDLIST apidl[5];
2821 for(count = 0; count < 5; count++)
2822 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
2827 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
2828 &IID_IDataObject, NULL, (void**)&pdo);
2829 ok(hres == S_OK, "got 0x%08x\n", hres);
2832 pidl = (void*)0xDEADBEEF;
2833 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
2834 ok(hres == S_OK, "got 0x%08x\n", hres);
2835 ok(pidl != NULL, "pidl is NULL.\n");
2836 ok(ILIsEqual(pidl, apidl[0]), "pidl not equal.\n");
2839 IDataObject_Release(pdo);
2843 skip("No files found - skipping single-file test.\n");
2847 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
2848 &IID_IDataObject, NULL, (void**)&pdo);
2849 ok(hres == S_OK, "got 0x%08x\n", hres);
2852 pidl = (void*)0xDEADBEEF;
2853 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
2854 ok(hres == E_NOINTERFACE || hres == E_FAIL /*Vista*/,
2855 "got 0x%08x\n", hres);
2856 ok(pidl == NULL, "pidl is not NULL.\n");
2858 IDataObject_Release(pdo);
2862 skip("zero or one file found - skipping multi-file test.\n");
2864 for(i = 0; i < count; i++)
2867 IEnumIDList_Release(peidl);
2870 IShellView_Release(psv);
2873 IShellFolder_Release(psfdesktop);
2874 pILFree(pidl_desktop);
2877 static void test_SHGetItemFromObject(void)
2879 IUnknownImpl *punkimpl;
2880 IShellFolder *psfdesktop;
2885 struct if_count ifaces[] =
2886 { {&IID_IPersistIDList, 0},
2887 {&IID_IPersistFolder2, 0},
2888 {&IID_IDataObject, 0},
2889 {&IID_IParentAndItem, 0},
2890 {&IID_IFolderView, 0},
2893 if(!pSHGetItemFromObject)
2895 skip("No SHGetItemFromObject.\n");
2899 SHGetDesktopFolder(&psfdesktop);
2903 /* Crashes with Windows 7 */
2904 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IUnknown, (void**)NULL);
2905 hres = pSHGetItemFromObject(NULL, &IID_IUnknown, (void**)NULL);
2906 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, NULL, (void**)&punk);
2909 hres = pSHGetItemFromObject(NULL, &IID_IUnknown, (void**)&punk);
2910 ok(hres == E_NOINTERFACE, "Got 0x%08x\n", hres);
2912 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
2913 punkimpl->lpVtbl = &vt_IUnknown;
2914 punkimpl->ifaces = ifaces;
2915 punkimpl->unknown = 0;
2917 /* The same as SHGetIDListFromObject */
2918 hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
2919 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
2920 ok(ifaces[0].count, "interface not requested.\n");
2921 ok(ifaces[1].count, "interface not requested.\n");
2922 ok(ifaces[2].count, "interface not requested.\n");
2924 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
2925 "interface not requested.\n");
2926 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
2927 "interface not requested.\n");
2929 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
2930 HeapFree(GetProcessHeap(), 0, punkimpl);
2932 /* Test IShellItem */
2933 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IShellItem, (void**)&psi);
2934 ok(hres == S_OK, "Got 0x%08x\n", hres);
2938 hres = pSHGetItemFromObject((IUnknown*)psi, &IID_IShellItem, (void**)&psi2);
2939 ok(hres == S_OK, "Got 0x%08x\n", hres);
2943 ok(psi == psi2, "Different instances (%p != %p).\n", psi, psi2);
2944 IShellItem_Release(psi2);
2946 IShellItem_Release(psi);
2949 IShellFolder_Release(psfdesktop);
2952 static void test_SHCreateShellItemArray(void)
2954 IShellFolder *pdesktopsf, *psf;
2955 IShellItemArray *psia;
2958 WCHAR cTestDirW[MAX_PATH];
2959 LPITEMIDLIST pidl_testdir, pidl;
2960 static const WCHAR testdirW[] = {'t','e','s','t','d','i','r',0};
2962 if(!pSHCreateShellItemArray) {
2963 skip("No pSHCreateShellItemArray!\n");
2967 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
2971 /* Crashes under native */
2972 pSHCreateShellItemArray(NULL, NULL, 0, NULL, NULL);
2973 pSHCreateShellItemArray(NULL, NULL, 1, NULL, NULL);
2974 pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, NULL);
2975 pSHCreateShellItemArray(pidl, NULL, 0, NULL, NULL);
2978 hr = pSHCreateShellItemArray(NULL, NULL, 0, NULL, &psia);
2979 ok(hr == E_POINTER, "got 0x%08x\n", hr);
2981 SHGetDesktopFolder(&pdesktopsf);
2982 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, &psia);
2983 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2985 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 1, NULL, &psia);
2986 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2988 pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
2989 hr = pSHCreateShellItemArray(pidl, NULL, 0, NULL, &psia);
2990 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2993 GetCurrentDirectoryW(MAX_PATH, cTestDirW);
2994 myPathAddBackslashW(cTestDirW);
2995 lstrcatW(cTestDirW, testdirW);
2997 CreateFilesFolders();
2999 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, cTestDirW, NULL, &pidl_testdir, 0);
3000 ok(hr == S_OK, "got 0x%08x\n", hr);
3003 hr = IShellFolder_BindToObject(pdesktopsf, pidl_testdir, NULL, (REFIID)&IID_IShellFolder,
3005 ok(hr == S_OK, "Got 0x%08x\n", hr);
3007 IShellFolder_Release(pdesktopsf);
3011 skip("Failed to set up environment for SHCreateShellItemArray tests.\n");
3012 pILFree(pidl_testdir);
3017 hr = IShellFolder_EnumObjects(psf, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &peidl);
3018 ok(hr == S_OK, "Got %08x\n", hr);
3021 LPITEMIDLIST apidl[5];
3022 UINT done, numitems, i;
3024 for(done = 0; done < 5; done++)
3025 if(IEnumIDList_Next(peidl, 1, &apidl[done], NULL) != S_OK)
3027 ok(done == 5, "Got %d pidls\n", done);
3028 IEnumIDList_Release(peidl);
3030 /* Create a ShellItemArray */
3031 hr = pSHCreateShellItemArray(NULL, psf, done, (LPCITEMIDLIST*)apidl, &psia);
3032 ok(hr == S_OK, "Got 0x%08x\n", hr);
3039 /* Crashes in Windows 7 */
3040 hr = IShellItemArray_GetCount(psia, NULL);
3043 IShellItemArray_GetCount(psia, &numitems);
3044 ok(numitems == done, "Got %d, expected %d\n", numitems, done);
3046 hr = IShellItemArray_GetItemAt(psia, numitems, &psi);
3047 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3049 /* Compare all the items */
3050 for(i = 0; i < numitems; i++)
3052 LPITEMIDLIST pidl_abs;
3053 pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3055 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3056 ok(hr == S_OK, "(%d) Failed with 0x%08x\n", i, hr);
3059 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3060 ok(hr == S_OK, "Got 0x%08x\n", hr);
3063 ok(ILIsEqual(pidl_abs, pidl), "Pidl not equal.\n");
3066 IShellItem_Release(psi);
3070 for(i = 0; i < done; i++)
3072 IShellItemArray_Release(psia);
3076 /* SHCreateShellItemArrayFromShellItem */
3077 if(pSHCreateShellItemArrayFromShellItem)
3083 /* Crashes under Windows 7 */
3084 hr = pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, NULL);
3085 hr = pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, (void**)&psia);
3086 hr = pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, NULL);
3089 hr = pSHCreateItemFromIDList(pidl_testdir, &IID_IShellItem, (void**)&psi);
3090 ok(hr == S_OK, "Got 0x%08x\n", hr);
3093 hr = pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, (void**)&psia);
3094 ok(hr == S_OK, "Got 0x%08x\n", hr);
3099 hr = IShellItemArray_GetCount(psia, &count);
3100 ok(hr == S_OK, "Got 0x%08x\n", hr);
3101 ok(count == 1, "Got count %d\n", count);
3102 hr = IShellItemArray_GetItemAt(psia, 0, &psi2);
3103 ok(hr == S_OK, "Got 0x%08x\n", hr);
3105 ok(psi != psi2, "ShellItems are of the same instance.\n");
3108 LPITEMIDLIST pidl1, pidl2;
3109 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl1);
3110 ok(hr == S_OK, "Got 0x%08x\n", hr);
3111 ok(pidl1 != NULL, "pidl1 was null.\n");
3112 hr = pSHGetIDListFromObject((IUnknown*)psi2, &pidl2);
3113 ok(hr == S_OK, "Got 0x%08x\n", hr);
3114 ok(pidl2 != NULL, "pidl2 was null.\n");
3115 ok(ILIsEqual(pidl1, pidl2), "pidls not equal.\n");
3118 IShellItem_Release(psi2);
3120 hr = IShellItemArray_GetItemAt(psia, 1, &psi2);
3121 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3122 IShellItemArray_Release(psia);
3124 IShellItem_Release(psi);
3128 skip("No SHCreateShellItemArrayFromShellItem.\n");
3130 if(pSHCreateShellItemArrayFromDataObject)
3136 /* Crashes under Windows 7 */
3137 hr = pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, NULL);
3139 hr = pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, (void**)&psia);
3140 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3142 hr = IShellFolder_CreateViewObject(psf, NULL, &IID_IShellView, (void**)&psv);
3143 ok(hr == S_OK, "got 0x%08x\n", hr);
3150 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3151 hr = IShellFolder_EnumObjects(psf, NULL, enum_flags, &peidl);
3152 ok(hr == S_OK, "got 0x%08x\n", hr);
3155 LPITEMIDLIST apidl[5];
3158 for(count = 0; count < 5; count++)
3159 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3161 ok(count == 5, "Got %d\n", count);
3165 hr = IShellFolder_GetUIObjectOf(psf, NULL, count, (LPCITEMIDLIST*)apidl,
3166 &IID_IDataObject, NULL, (void**)&pdo);
3167 ok(hr == S_OK, "Got 0x%08x\n", hr);
3170 hr = pSHCreateShellItemArrayFromDataObject(pdo, &IID_IShellItemArray,
3172 ok(hr == S_OK, "Got 0x%08x\n", hr);
3176 hr = IShellItemArray_GetCount(psia, &count_sia);
3177 ok(count_sia == count, "Counts differ (%d, %d)\n", count, count_sia);
3178 for(i = 0; i < count_sia; i++)
3180 LPITEMIDLIST pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3182 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3183 ok(hr == S_OK, "Got 0x%08x\n", hr);
3187 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3188 ok(hr == S_OK, "Got 0x%08x\n", hr);
3189 ok(pidl != NULL, "pidl as NULL.\n");
3190 ok(ILIsEqual(pidl, pidl_abs), "pidls differ.\n");
3192 IShellItem_Release(psi);
3197 IShellItemArray_Release(psia);
3200 IDataObject_Release(pdo);
3202 for(i = 0; i < count; i++)
3206 skip("No files found - skipping test.\n");
3208 IEnumIDList_Release(peidl);
3210 IShellView_Release(psv);
3214 skip("No SHCreateShellItemArrayFromDataObject.\n");
3216 IShellFolder_Release(psf);
3217 pILFree(pidl_testdir);
3221 static void test_ShellItemBindToHandler(void)
3224 LPITEMIDLIST pidl_desktop;
3227 if(!pSHCreateShellItem)
3229 skip("SHCreateShellItem missing.\n");
3233 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3234 ok(hr == S_OK, "Got 0x%08x\n", hr);
3237 hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
3238 ok(hr == S_OK, "Got 0x%08x\n", hr);
3242 IPersistFolder2 *ppf2;
3247 /* Crashes under Windows 7 */
3248 hr = IShellItem_BindToHandler(psi, NULL, NULL, NULL, NULL);
3249 hr = IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, NULL);
3251 hr = IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, (void**)&punk);
3252 ok(hr == MK_E_NOOBJECT, "Got 0x%08x\n", hr);
3255 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IShellFolder, (void**)&punk);
3256 ok(hr == S_OK, "Got 0x%08x\n", hr);
3257 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3258 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IPersistFolder2, (void**)&ppf2);
3259 ok(hr == S_OK, "Got 0x%08x\n", hr);
3262 LPITEMIDLIST pidl_tmp;
3263 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl_tmp);
3264 ok(hr == S_OK, "Got 0x%08x\n", hr);
3267 ok(ILIsEqual(pidl_desktop, pidl_tmp), "Pidl not equal (%p, %p)\n", pidl_desktop, pidl_tmp);
3270 IPersistFolder2_Release(ppf2);
3275 /* BHID_SFUIObject */
3276 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IDataObject, (void**)&punk);
3277 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3278 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3279 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IContextMenu, (void**)&punk);
3280 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3281 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3283 /* BHID_SFViewObject */
3284 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellView, (void**)&punk);
3285 ok(hr == S_OK, "Got 0x%08x\n", hr);
3286 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3287 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellFolderView, (void**)&punk);
3288 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3289 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3292 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IStream, (void**)&punk);
3293 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3294 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3295 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IUnknown, (void**)&punk);
3296 ok(hr == S_OK, "Got 0x%08x\n", hr);
3297 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3300 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IStream, (void**)&punk);
3301 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3302 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3303 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IUnknown, (void**)&punk);
3304 ok(hr == S_OK, "Got 0x%08x\n", hr);
3305 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3307 /* BHID_StorageEnum */
3308 hr = IShellItem_BindToHandler(psi, NULL, &BHID_StorageEnum, &IID_IEnumShellItems, (void**)&punk);
3309 ok(hr == S_OK, "Got 0x%08x\n", hr);
3310 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3313 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_IUnknown, (void**)&punk);
3314 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3315 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3317 /* BHID_EnumItems */
3318 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumItems, &IID_IEnumShellItems, (void**)&punk);
3319 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3320 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3322 /* BHID_DataObject */
3323 hr = IShellItem_BindToHandler(psi, NULL, &BHID_DataObject, &IID_IDataObject, (void**)&punk);
3324 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3325 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3328 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Filter, &IID_IUnknown, (void**)&punk);
3329 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3330 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3332 /* BHID_LinkTargetItem */
3333 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IShellItem, (void**)&punk);
3334 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3335 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3336 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IUnknown, (void**)&punk);
3337 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3338 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3340 /* BHID_PropertyStore */
3341 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStore, (void**)&punk);
3342 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3343 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3344 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStoreFactory, (void**)&punk);
3345 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3346 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3348 /* BHID_ThumbnailHandler */
3349 hr = IShellItem_BindToHandler(psi, NULL, &BHID_ThumbnailHandler, &IID_IUnknown, (void**)&punk);
3350 ok(hr == E_INVALIDARG || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3351 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3353 /* BHID_AssociationArray */
3354 hr = IShellItem_BindToHandler(psi, NULL, &BHID_AssociationArray, &IID_IQueryAssociations, (void**)&punk);
3355 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3356 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3358 /* BHID_EnumAssocHandlers */
3359 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumAssocHandlers, &IID_IUnknown, (void**)&punk);
3360 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3361 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3364 IShellItem_Release(psi);
3367 skip("Failed to create ShellItem.\n");
3369 pILFree(pidl_desktop);
3372 static void test_SHParseDisplayName(void)
3374 LPITEMIDLIST pidl1, pidl2;
3375 IShellFolder *desktop;
3376 WCHAR dirW[MAX_PATH];
3381 if (!pSHParseDisplayName)
3383 win_skip("SHParseDisplayName isn't available\n");
3389 /* crashes on native */
3390 hr = pSHParseDisplayName(NULL, NULL, NULL, 0, NULL);
3392 hr = pSHParseDisplayName(nameW, NULL, NULL, 0, NULL);
3395 pidl1 = (LPITEMIDLIST)0xdeadbeef;
3396 hr = pSHParseDisplayName(NULL, NULL, &pidl1, 0, NULL);
3397 ok(broken(hr == E_OUTOFMEMORY) /* < Vista */ ||
3398 hr == E_INVALIDARG, "failed %08x\n", hr);
3399 ok(pidl1 == 0, "expected null ptr, got %p\n", pidl1);
3403 hr = pSHParseDisplayName(nameW, NULL, &pidl1, 0, NULL);
3404 ok(hr == S_OK, "failed %08x\n", hr);
3405 hr = SHGetDesktopFolder(&desktop);
3406 ok(hr == S_OK, "failed %08x\n", hr);
3407 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, nameW, NULL, &pidl2, NULL);
3408 ok(hr == S_OK, "failed %08x\n", hr);
3409 ret = pILIsEqual(pidl1, pidl2);
3410 ok(ret == TRUE, "expected equal idls\n");
3415 GetWindowsDirectoryW( dirW, MAX_PATH );
3417 hr = pSHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
3418 ok(hr == S_OK, "failed %08x\n", hr);
3419 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, dirW, NULL, &pidl2, NULL);
3420 ok(hr == S_OK, "failed %08x\n", hr);
3422 ret = pILIsEqual(pidl1, pidl2);
3423 ok(ret == TRUE, "expected equal idls\n");
3427 IShellFolder_Release(desktop);
3430 static void test_desktop_IPersist(void)
3432 IShellFolder *desktop;
3434 IPersistFolder2 *ppf2;
3438 hr = SHGetDesktopFolder(&desktop);
3439 ok(hr == S_OK, "failed %08x\n", hr);
3441 hr = IShellFolder_QueryInterface(desktop, &IID_IPersist, (void**)&persist);
3442 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* NT4, W9X */, "failed %08x\n", hr);
3448 /* crashes on native */
3449 hr = IPersist_GetClassID(persist, NULL);
3451 memset(&clsid, 0, sizeof(clsid));
3452 hr = IPersist_GetClassID(persist, &clsid);
3453 ok(hr == S_OK, "failed %08x\n", hr);
3454 ok(IsEqualIID(&CLSID_ShellDesktop, &clsid), "Expected CLSID_ShellDesktop\n");
3455 IPersist_Release(persist);
3458 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder2, (void**)&ppf2);
3459 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* pre-Vista */, "failed %08x\n", hr);
3462 IPersistFolder *ppf;
3464 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder, (void**)&ppf);
3465 ok(hr == S_OK, "IID_IPersistFolder2 without IID_IPersistFolder.\n");
3467 IPersistFolder_Release(ppf);
3470 hr = IPersistFolder2_Initialize(ppf2, NULL);
3471 ok(hr == S_OK, "got %08x\n", hr);
3475 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl);
3476 ok(hr == S_OK, "got %08x\n", hr);
3477 ok(pidl != NULL, "pidl was NULL.\n");
3478 if(SUCCEEDED(hr)) pILFree(pidl);
3480 IPersistFolder2_Release(ppf2);
3483 IShellFolder_Release(desktop);
3486 static void test_GetUIObject(void)
3488 IShellFolder *psf_desktop;
3492 WCHAR path[MAX_PATH];
3493 const WCHAR filename[] =
3494 {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
3496 if(!pSHBindToParent)
3498 win_skip("SHBindToParent missing.\n");
3502 GetCurrentDirectoryW(MAX_PATH, path);
3505 skip("GetCurrentDirectoryW returned an empty string.\n");
3508 lstrcatW(path, filename);
3509 SHGetDesktopFolder(&psf_desktop);
3511 CreateFilesFolders();
3513 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, path, NULL, &pidl, 0);
3514 ok(hr == S_OK || broken(hr == E_FAIL) /* WinME */, "Got 0x%08x\n", hr);
3518 LPCITEMIDLIST pidl_child;
3519 hr = pSHBindToParent(pidl, &IID_IShellFolder, (void**)&psf, &pidl_child);
3520 ok(hr == S_OK, "Got 0x%08x\n", hr);
3523 hr = IShellFolder_GetUIObjectOf(psf, NULL, 1, (LPCITEMIDLIST*)&pidl_child,
3524 &IID_IContextMenu, NULL, (void**)&pcm);
3525 ok(hr == S_OK, "Got 0x%08x\n", hr);
3528 HMENU hmenu = CreatePopupMenu();
3529 INT max_id, max_id_check;
3531 const int id_upper_limit = 32767;
3532 hr = IContextMenu_QueryContextMenu(pcm, hmenu, 0, 0, id_upper_limit, CMF_NORMAL);
3533 ok(SUCCEEDED(hr), "Got 0x%08x\n", hr);
3534 max_id = HRESULT_CODE(hr) - 1; /* returns max_id + 1 */
3535 ok(max_id <= id_upper_limit, "Got %d\n", max_id);
3536 count = GetMenuItemCount(hmenu);
3537 ok(count, "Got %d\n", count);
3540 for(i = 0; i < count; i++)
3544 ZeroMemory(&mii, sizeof(MENUITEMINFOA));
3545 mii.cbSize = sizeof(MENUITEMINFOA);
3546 mii.fMask = MIIM_ID | MIIM_FTYPE;
3549 res = GetMenuItemInfoA(hmenu, i, TRUE, &mii);
3550 ok(res, "Failed (last error: %d).\n", GetLastError());
3552 ok( (mii.wID <= id_upper_limit) || (mii.fType & MFT_SEPARATOR),
3553 "Got non-separator ID out of range: %d (type: %x) \n", mii.wID, mii.fType);
3554 if(!(mii.fType & MFT_SEPARATOR))
3555 max_id_check = (mii.wID>max_id_check)?mii.wID:max_id_check;
3557 ok((max_id_check == max_id) ||
3558 (max_id_check == max_id-1 /* Win 7 */),
3559 "Not equal (or near equal), got %d and %d\n", max_id_check, max_id);
3561 #define is_win2k() (pSHGetFolderPathA && !pSHGetFolderPathAndSubDirA)
3563 if(count && !is_win2k()) /* Test is interactive on w2k, so skip */
3565 CMINVOKECOMMANDINFO cmi;
3566 ZeroMemory(&cmi, sizeof(CMINVOKECOMMANDINFO));
3567 cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
3569 /* Attempt to execute a nonexistent command */
3570 cmi.lpVerb = MAKEINTRESOURCEA(9999);
3571 hr = IContextMenu_InvokeCommand(pcm, &cmi);
3572 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3574 cmi.lpVerb = "foobar_wine_test";
3575 hr = IContextMenu_InvokeCommand(pcm, &cmi);
3576 ok( (hr == E_INVALIDARG) || (hr == E_FAIL /* Win7 */) ||
3577 (hr == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION) /* Vista */),
3578 "Got 0x%08x\n", hr);
3583 IContextMenu_Release(pcm);
3585 IShellFolder_Release(psf);
3587 if(pILFree) pILFree(pidl);
3590 IShellFolder_Release(psf_desktop);
3594 #define verify_pidl(i,p) r_verify_pidl(__LINE__, i, p)
3595 static void r_verify_pidl(unsigned l, LPCITEMIDLIST pidl, const WCHAR *path)
3597 LPCITEMIDLIST child;
3598 IShellFolder *parent;
3602 if(!pSHBindToParent){
3603 win_skip("SHBindToParent is not available, not performing full PIDL verification\n");
3605 ok_(__FILE__,l)(pidl != NULL, "Expected PIDL to be non-NULL\n");
3607 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
3613 ok_(__FILE__,l)(0, "didn't get expected path (%s), instead: NULL\n", wine_dbgstr_w(path));
3617 hr = pSHBindToParent(pidl, &IID_IShellFolder, (LPVOID*)&parent, &child);
3618 ok_(__FILE__,l)(hr == S_OK, "SHBindToParent failed: 0x%08x\n", hr);
3622 hr = IShellFolder_GetDisplayNameOf(parent, child, SHGDN_FORPARSING, &filename);
3623 ok_(__FILE__,l)(hr == S_OK, "GetDisplayNameOf failed: 0x%08x\n", hr);
3625 IShellFolder_Release(parent);
3629 ok_(__FILE__,l)(filename.uType == STRRET_WSTR || filename.uType == STRRET_CSTR,
3630 "Got unexpected string type: %d\n", filename.uType);
3631 if(filename.uType == STRRET_WSTR){
3632 ok_(__FILE__,l)(lstrcmpW(path, filename.pOleStr) == 0,
3633 "didn't get expected path (%s), instead: %s\n",
3634 wine_dbgstr_w(path), wine_dbgstr_w(filename.pOleStr));
3635 }else if(filename.uType == STRRET_CSTR){
3636 ok_(__FILE__,l)(strcmp_wa(path, filename.cStr) == 0,
3637 "didn't get expected path (%s), instead: %s\n",
3638 wine_dbgstr_w(path), filename.cStr);
3641 IShellFolder_Release(parent);
3643 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
3646 static void test_SHSimpleIDListFromPath(void)
3648 const WCHAR adirW[] = {'C',':','\\','s','i','d','l','f','p','d','i','r',0};
3649 const CHAR adirA[] = "C:\\sidlfpdir";
3650 BOOL br, is_unicode = !(GetVersion() & 0x80000000);
3652 LPITEMIDLIST pidl = NULL;
3654 if(!pSHSimpleIDListFromPathAW){
3655 win_skip("SHSimpleIDListFromPathAW not available\n");
3659 br = CreateDirectoryA(adirA, NULL);
3660 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
3663 pidl = pSHSimpleIDListFromPathAW(adirW);
3665 pidl = pSHSimpleIDListFromPathAW(adirA);
3666 verify_pidl(pidl, adirW);
3669 br = RemoveDirectoryA(adirA);
3670 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
3673 pidl = pSHSimpleIDListFromPathAW(adirW);
3675 pidl = pSHSimpleIDListFromPathAW(adirA);
3676 verify_pidl(pidl, adirW);
3680 /* IFileSystemBindData impl */
3681 static HRESULT WINAPI fsbd_QueryInterface(IFileSystemBindData *fsbd,
3682 REFIID riid, void **ppv)
3684 if(IsEqualIID(riid, &IID_IFileSystemBindData) ||
3685 IsEqualIID(riid, &IID_IUnknown)){
3689 return E_NOINTERFACE;
3692 static ULONG WINAPI fsbd_AddRef(IFileSystemBindData *fsbd)
3697 static ULONG WINAPI fsbd_Release(IFileSystemBindData *fsbd)
3702 static HRESULT WINAPI fsbd_SetFindData(IFileSystemBindData *fsbd,
3703 const WIN32_FIND_DATAW *pfd)
3705 ok(0, "SetFindData called\n");
3709 static HRESULT WINAPI fsbd_GetFindData_nul(IFileSystemBindData *fsbd,
3710 WIN32_FIND_DATAW *pfd)
3712 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
3716 static HRESULT WINAPI fsbd_GetFindData_junk(IFileSystemBindData *fsbd,
3717 WIN32_FIND_DATAW *pfd)
3719 memset(pfd, 0xdeadbeef, sizeof(WIN32_FIND_DATAW));
3723 static HRESULT WINAPI fsbd_GetFindData_invalid(IFileSystemBindData *fsbd,
3724 WIN32_FIND_DATAW *pfd)
3726 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
3727 *pfd->cFileName = 'a';
3728 *pfd->cAlternateFileName = 'a';
3732 static HRESULT WINAPI fsbd_GetFindData_valid(IFileSystemBindData *fsbd,
3733 WIN32_FIND_DATAW *pfd)
3735 static const WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
3736 HANDLE handle = FindFirstFileW(adirW, pfd);
3741 static HRESULT WINAPI fsbd_GetFindData_fail(IFileSystemBindData *fsbd,
3742 WIN32_FIND_DATAW *pfd)
3747 static IFileSystemBindDataVtbl fsbdVtbl = {
3748 fsbd_QueryInterface,
3755 static IFileSystemBindData fsbd = { &fsbdVtbl };
3757 static void test_ParseDisplayNamePBC(void)
3759 WCHAR wFileSystemBindData[] =
3760 {'F','i','l','e',' ','S','y','s','t','e','m',' ','B','i','n','d',' ','D','a','t','a',0};
3761 WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
3762 const HRESULT exp_err = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
3769 /* Check if we support WCHAR functions */
3770 SetLastError(0xdeadbeef);
3771 lstrcmpiW(adirW, adirW);
3772 if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED){
3773 win_skip("Most W-calls are not implemented\n");
3777 hres = SHGetDesktopFolder(&psf);
3778 ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
3780 win_skip("Failed to get IShellFolder, can't run tests\n");
3784 /* fails on unknown dir with no IBindCtx */
3785 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, adirW, NULL, &pidl, NULL);
3786 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
3787 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
3789 /* fails on unknown dir with IBindCtx with no IFileSystemBindData */
3790 hres = CreateBindCtx(0, &pbc);
3791 ok(hres == S_OK, "CreateBindCtx failed: 0x%08x\n", hres);
3793 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3794 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
3795 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
3797 /* unknown dir with IBindCtx with IFileSystemBindData */
3798 hres = IBindCtx_RegisterObjectParam(pbc, wFileSystemBindData, (IUnknown*)&fsbd);
3799 ok(hres == S_OK, "RegisterObjectParam failed: 0x%08x\n", hres);
3801 /* return E_FAIL from GetFindData */
3802 pidl = (ITEMIDLIST*)0xdeadbeef;
3803 fsbdVtbl.GetFindData = fsbd_GetFindData_fail;
3804 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3805 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
3806 "ParseDisplayName failed: 0x%08x\n", hres);
3807 if(SUCCEEDED(hres)){
3808 verify_pidl(pidl, adirW);
3812 /* set FIND_DATA struct to NULLs */
3813 pidl = (ITEMIDLIST*)0xdeadbeef;
3814 fsbdVtbl.GetFindData = fsbd_GetFindData_nul;
3815 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3816 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
3817 "ParseDisplayName failed: 0x%08x\n", hres);
3818 if(SUCCEEDED(hres)){
3819 verify_pidl(pidl, adirW);
3823 /* set FIND_DATA struct to junk */
3824 pidl = (ITEMIDLIST*)0xdeadbeef;
3825 fsbdVtbl.GetFindData = fsbd_GetFindData_junk;
3826 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3827 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
3828 "ParseDisplayName failed: 0x%08x\n", hres);
3829 if(SUCCEEDED(hres)){
3830 verify_pidl(pidl, adirW);
3834 /* set FIND_DATA struct to invalid data */
3835 pidl = (ITEMIDLIST*)0xdeadbeef;
3836 fsbdVtbl.GetFindData = fsbd_GetFindData_invalid;
3837 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3838 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
3839 "ParseDisplayName failed: 0x%08x\n", hres);
3840 if(SUCCEEDED(hres)){
3841 verify_pidl(pidl, adirW);
3845 /* set FIND_DATA struct to valid data */
3846 pidl = (ITEMIDLIST*)0xdeadbeef;
3847 fsbdVtbl.GetFindData = fsbd_GetFindData_valid;
3848 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3849 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
3850 "ParseDisplayName failed: 0x%08x\n", hres);
3851 if(SUCCEEDED(hres)){
3852 verify_pidl(pidl, adirW);
3856 IBindCtx_Release(pbc);
3857 IShellFolder_Release(psf);
3860 static const CHAR testwindow_class[] = "testwindow";
3861 #define WM_USER_NOTIFY (WM_APP+1)
3867 const WCHAR *path_1;
3868 const WCHAR *path_2;
3871 static LRESULT CALLBACK testwindow_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
3873 UINT signal = (UINT)lparam;
3876 case WM_USER_NOTIFY:
3877 if(exp_data.exp_notify){
3878 LPCITEMIDLIST *pidls = (LPCITEMIDLIST*)wparam;
3880 ok(exp_data.signal == signal,
3881 "%s: expected notification type %x, got: %x\n",
3882 exp_data.id, exp_data.signal, signal);
3884 trace("verifying pidls for: %s\n", exp_data.id);
3885 verify_pidl(pidls[0], exp_data.path_1);
3886 verify_pidl(pidls[1], exp_data.path_2);
3888 exp_data.exp_notify = FALSE;
3890 ok(exp_data.exp_notify, "Didn't expect a WM_USER_NOTIFY message (event: %x)\n", signal);
3893 return DefWindowProc(hwnd, msg, wparam, lparam);
3896 static void register_testwindow_class(void)
3901 ZeroMemory(&cls, sizeof(cls));
3902 cls.cbSize = sizeof(cls);
3904 cls.lpfnWndProc = testwindow_wndproc;
3905 cls.hInstance = GetModuleHandleA(NULL);
3906 cls.lpszClassName = testwindow_class;
3909 ret = RegisterClassExA(&cls);
3910 ok(ret != 0, "RegisterClassExA failed: %d\n", GetLastError());
3913 /* SHCNF_FLUSH doesn't seem to work as advertised for SHCNF_PATHA, so we
3914 * have to poll repeatedly for the message to appear */
3915 static void do_events(void)
3918 while (exp_data.exp_notify && (c++ < 10)){
3920 while(PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)){
3921 TranslateMessage(&msg);
3922 DispatchMessageA(&msg);
3924 if(exp_data.exp_notify)
3927 trace("%s: took %d tries\n", exp_data.id, c);
3930 static void test_SHChangeNotify(void)
3935 BOOL br, has_unicode;
3936 SHChangeNotifyEntry entries[1];
3937 const CHAR root_dirA[] = "C:\\shell32_cn_test";
3938 const WCHAR root_dirW[] = {'C',':','\\','s','h','e','l','l','3','2','_','c','n','_','t','e','s','t',0};
3939 const CHAR test_dirA[] = "C:\\shell32_cn_test\\test";
3940 const WCHAR test_dirW[] = {'C',':','\\','s','h','e','l','l','3','2','_','c','n','_','t','e','s','t','\\','t','e','s','t',0};
3942 CreateDirectoryW(NULL, NULL);
3943 has_unicode = !(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED);
3945 /* set up the root directory & window */
3946 br = CreateDirectoryA(root_dirA, NULL);
3947 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
3949 register_testwindow_class();
3951 wnd = CreateWindowExA(0, testwindow_class, testwindow_class, 0,
3952 CW_USEDEFAULT, CW_USEDEFAULT, 130, 105,
3953 NULL, NULL, GetModuleHandleA(NULL), 0);
3954 ok(wnd != NULL, "Failed to make a window\n");
3956 entries[0].pidl = NULL;
3958 hr = SHILCreateFromPath(root_dirW, (LPITEMIDLIST*)&entries[0].pidl, 0);
3960 hr = SHILCreateFromPath((LPCVOID)root_dirA, (LPITEMIDLIST*)&entries[0].pidl, 0);
3961 ok(hr == S_OK, "SHILCreateFromPath failed: 0x%08x\n", hr);
3962 entries[0].fRecursive = TRUE;
3964 notifyID = SHChangeNotifyRegister(wnd, SHCNRF_ShellLevel,
3965 SHCNE_ALLEVENTS, WM_USER_NOTIFY, 1, entries);
3966 ok(notifyID != 0, "Failed to register a window for change notifications\n");
3969 br = CreateDirectoryA(test_dirA, NULL);
3970 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
3973 exp_data.id = "MKDIR PATHW";
3974 exp_data.signal = SHCNE_MKDIR;
3975 exp_data.exp_notify = TRUE;
3976 exp_data.path_1 = test_dirW;
3977 exp_data.path_2 = NULL;
3978 SHChangeNotify(SHCNE_MKDIR, SHCNF_PATHW | SHCNF_FLUSH, test_dirW, NULL);
3980 ok(exp_data.exp_notify == FALSE, "Expected wndproc to be called\n");
3982 win_skip("skipping WCHAR tests\n");
3984 exp_data.id = "MKDIR PATHA";
3985 exp_data.signal = SHCNE_MKDIR;
3986 exp_data.exp_notify = TRUE;
3987 exp_data.path_1 = test_dirW;
3988 exp_data.path_2 = NULL;
3989 SHChangeNotify(SHCNE_MKDIR, SHCNF_PATHA | SHCNF_FLUSH, test_dirA, NULL);
3991 ok(exp_data.exp_notify == FALSE, "Expected wndproc to be called\n");
3994 br = RemoveDirectoryA(test_dirA);
3995 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
3998 exp_data.id = "RMDIR PATHW";
3999 exp_data.signal = SHCNE_RMDIR;
4000 exp_data.exp_notify = TRUE;
4001 exp_data.path_1 = test_dirW;
4002 exp_data.path_2 = NULL;
4003 SHChangeNotify(SHCNE_RMDIR, SHCNF_PATHW | SHCNF_FLUSH, test_dirW, NULL);
4005 ok(exp_data.exp_notify == FALSE, "Expected wndproc to be called\n");
4007 win_skip("skipping WCHAR tests\n");
4009 exp_data.id = "RMDIR PATHA";
4010 exp_data.signal = SHCNE_RMDIR;
4011 exp_data.exp_notify = TRUE;
4012 exp_data.path_1 = test_dirW;
4013 exp_data.path_2 = NULL;
4014 SHChangeNotify(SHCNE_RMDIR, SHCNF_PATHA | SHCNF_FLUSH, test_dirA, NULL);
4016 ok(exp_data.exp_notify == FALSE, "Expected wndproc to be called\n");
4018 SHChangeNotifyDeregister(notifyID);
4021 br = RemoveDirectoryA(root_dirA);
4022 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4025 START_TEST(shlfolder)
4027 init_function_pointers();
4028 /* if OleInitialize doesn't get called, ParseDisplayName returns
4029 CO_E_NOTINITIALIZED for malformed directory names on win2k. */
4030 OleInitialize(NULL);
4032 test_ParseDisplayName();
4033 test_SHParseDisplayName();
4034 test_BindToObject();
4035 test_EnumObjects_and_CompareIDs();
4036 test_GetDisplayName();
4037 test_GetAttributesOf();
4038 test_SHGetPathFromIDList();
4039 test_CallForAttributes();
4040 test_FolderShortcut();
4041 test_ITEMIDLIST_format();
4042 test_SHGetFolderPathAndSubDirA();
4043 test_LocalizedNames();
4044 test_SHCreateShellItem();
4045 test_SHCreateShellItemArray();
4046 test_desktop_IPersist();
4048 test_SHSimpleIDListFromPath();
4049 test_ParseDisplayNamePBC();
4050 test_SHGetNameFromIDList();
4051 test_SHGetItemFromDataObject();
4052 test_SHGetIDListFromObject();
4053 test_SHGetItemFromObject();
4054 test_ShellItemCompare();
4055 test_SHChangeNotify();
4056 test_ShellItemBindToHandler();