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 *pSHCreateShellItemArrayFromShellItem)(IShellItem*, REFIID, void **);
63 static LPITEMIDLIST (WINAPI *pILCombine)(LPCITEMIDLIST,LPCITEMIDLIST);
64 static HRESULT (WINAPI *pSHParseDisplayName)(LPCWSTR,IBindCtx*,LPITEMIDLIST*,SFGAOF,SFGAOF*);
65 static LPITEMIDLIST (WINAPI *pSHSimpleIDListFromPathAW)(LPCVOID);
66 static HRESULT (WINAPI *pSHGetNameFromIDList)(PCIDLIST_ABSOLUTE,SIGDN,PWSTR*);
67 static HRESULT (WINAPI *pSHGetItemFromDataObject)(IDataObject*,DATAOBJ_GET_ITEM_FLAGS,REFIID,void**);
68 static HRESULT (WINAPI *pSHGetIDListFromObject)(IUnknown*, PIDLIST_ABSOLUTE*);
69 static HRESULT (WINAPI *pSHGetItemFromObject)(IUnknown*,REFIID,void**);
71 static void init_function_pointers(void)
77 hmod = GetModuleHandleA("shell32.dll");
79 #define MAKEFUNC(f) (p##f = (void*)GetProcAddress(hmod, #f))
80 MAKEFUNC(SHBindToParent);
81 MAKEFUNC(SHCreateItemFromIDList);
82 MAKEFUNC(SHCreateItemFromParsingName);
83 MAKEFUNC(SHCreateShellItem);
84 MAKEFUNC(SHCreateShellItemArray);
85 MAKEFUNC(SHCreateShellItemArrayFromShellItem);
86 MAKEFUNC(SHGetFolderPathA);
87 MAKEFUNC(SHGetFolderPathAndSubDirA);
88 MAKEFUNC(SHGetPathFromIDListW);
89 MAKEFUNC(SHGetSpecialFolderPathA);
90 MAKEFUNC(SHGetSpecialFolderPathW);
91 MAKEFUNC(SHGetSpecialFolderLocation);
92 MAKEFUNC(SHParseDisplayName);
93 MAKEFUNC(SHGetNameFromIDList);
94 MAKEFUNC(SHGetItemFromDataObject);
95 MAKEFUNC(SHGetIDListFromObject);
96 MAKEFUNC(SHGetItemFromObject);
99 #define MAKEFUNC_ORD(f, ord) (p##f = (void*)GetProcAddress(hmod, (LPSTR)(ord)))
100 MAKEFUNC_ORD(ILFindLastID, 16);
101 MAKEFUNC_ORD(ILIsEqual, 21);
102 MAKEFUNC_ORD(ILCombine, 25);
103 MAKEFUNC_ORD(ILFree, 155);
104 MAKEFUNC_ORD(SHSimpleIDListFromPathAW, 162);
107 /* test named exports */
108 ptr = GetProcAddress(hmod, "ILFree");
109 ok(broken(ptr == 0) || ptr != 0, "expected named export for ILFree\n");
112 #define TESTNAMED(f) \
113 ptr = (void*)GetProcAddress(hmod, #f); \
114 ok(ptr != 0, "expected named export for " #f "\n");
116 TESTNAMED(ILAppendID);
118 TESTNAMED(ILCloneFirst);
119 TESTNAMED(ILCombine);
120 TESTNAMED(ILCreateFromPath);
121 TESTNAMED(ILCreateFromPathA);
122 TESTNAMED(ILCreateFromPathW);
123 TESTNAMED(ILFindChild);
124 TESTNAMED(ILFindLastID);
125 TESTNAMED(ILGetNext);
126 TESTNAMED(ILGetSize);
127 TESTNAMED(ILIsEqual);
128 TESTNAMED(ILIsParent);
129 TESTNAMED(ILRemoveLastID);
130 TESTNAMED(ILSaveToStream);
134 hmod = GetModuleHandleA("shlwapi.dll");
135 pStrRetToBufW = (void*)GetProcAddress(hmod, "StrRetToBufW");
137 hr = SHGetMalloc(&ppM);
138 ok(hr == S_OK, "SHGetMalloc failed %08x\n", hr);
141 static void test_ParseDisplayName(void)
144 IShellFolder *IDesktopFolder;
145 static const char *cNonExistDir1A = "c:\\nonexist_subdir";
146 static const char *cNonExistDir2A = "c:\\\\nonexist_subdir";
147 static const char *cInetTestA = "http:\\yyy";
148 static const char *cInetTest2A = "xx:yyy";
150 WCHAR cTestDirW [MAX_PATH] = {0};
154 hr = SHGetDesktopFolder(&IDesktopFolder);
155 ok(hr == S_OK, "Expected SHGetDesktopFolder to return S_OK, got 0x%08x\n", hr);
156 if(hr != S_OK) return;
158 /* Tests crash on W2K and below (SHCreateShellItem available as of XP) */
159 if (pSHCreateShellItem)
161 /* null name and pidl */
162 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
163 NULL, NULL, NULL, NULL, NULL, 0);
164 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
167 newPIDL = (ITEMIDLIST*)0xdeadbeef;
168 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
169 NULL, NULL, NULL, NULL, &newPIDL, 0);
170 ok(newPIDL == 0, "expected null, got %p\n", newPIDL);
171 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
174 win_skip("Tests would crash on W2K and below\n");
176 MultiByteToWideChar(CP_ACP, 0, cInetTestA, -1, cTestDirW, MAX_PATH);
177 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
178 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
179 todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
180 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
183 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
184 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
185 IMalloc_Free(ppM, newPIDL);
188 MultiByteToWideChar(CP_ACP, 0, cInetTest2A, -1, cTestDirW, MAX_PATH);
189 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
190 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
191 todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
192 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
195 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
196 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
197 IMalloc_Free(ppM, newPIDL);
200 res = GetFileAttributesA(cNonExistDir1A);
201 if(res != INVALID_FILE_ATTRIBUTES)
203 skip("Test directory unexpectedly exists\n");
207 MultiByteToWideChar(CP_ACP, 0, cNonExistDir1A, -1, cTestDirW, MAX_PATH);
208 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
209 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
210 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL),
211 "ParseDisplayName returned %08x, expected 80070002 or E_FAIL\n", hr);
213 res = GetFileAttributesA(cNonExistDir2A);
214 if(res != INVALID_FILE_ATTRIBUTES)
216 skip("Test directory unexpectedly exists\n");
220 MultiByteToWideChar(CP_ACP, 0, cNonExistDir2A, -1, cTestDirW, MAX_PATH);
221 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
222 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
223 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL) || (hr == E_INVALIDARG),
224 "ParseDisplayName returned %08x, expected 80070002, E_FAIL or E_INVALIDARG\n", hr);
226 /* I thought that perhaps the DesktopFolder's ParseDisplayName would recognize the
227 * path corresponding to CSIDL_PERSONAL and return a CLSID_MyDocuments PIDL. Turns
228 * out it doesn't. The magic seems to happen in the file dialogs, then. */
229 if (!pSHGetSpecialFolderPathW || !pILFindLastID)
231 win_skip("SHGetSpecialFolderPathW and/or ILFindLastID are not available\n");
235 bRes = pSHGetSpecialFolderPathW(NULL, cTestDirW, CSIDL_PERSONAL, FALSE);
236 ok(bRes, "SHGetSpecialFolderPath(CSIDL_PERSONAL) failed! %u\n", GetLastError());
237 if (!bRes) goto finished;
239 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
240 ok(hr == S_OK, "DesktopFolder->ParseDisplayName failed. hr = %08x.\n", hr);
241 if (hr != S_OK) goto finished;
243 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x31 ||
244 pILFindLastID(newPIDL)->mkid.abID[0] == 0xb1, /* Win98 */
245 "Last pidl should be of type PT_FOLDER or PT_IESPECIAL2, but is: %02x\n",
246 pILFindLastID(newPIDL)->mkid.abID[0]);
247 IMalloc_Free(ppM, newPIDL);
250 IShellFolder_Release(IDesktopFolder);
253 /* creates a file with the specified name for tests */
254 static void CreateTestFile(const CHAR *name)
259 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
260 if (file != INVALID_HANDLE_VALUE)
262 WriteFile(file, name, strlen(name), &written, NULL);
263 WriteFile(file, "\n", strlen("\n"), &written, NULL);
269 /* initializes the tests */
270 static void CreateFilesFolders(void)
272 CreateDirectoryA(".\\testdir", NULL);
273 CreateDirectoryA(".\\testdir\\test.txt", NULL);
274 CreateTestFile (".\\testdir\\test1.txt ");
275 CreateTestFile (".\\testdir\\test2.txt ");
276 CreateTestFile (".\\testdir\\test3.txt ");
277 CreateDirectoryA(".\\testdir\\testdir2 ", NULL);
278 CreateDirectoryA(".\\testdir\\testdir2\\subdir", NULL);
281 /* cleans after tests */
282 static void Cleanup(void)
284 DeleteFileA(".\\testdir\\test1.txt");
285 DeleteFileA(".\\testdir\\test2.txt");
286 DeleteFileA(".\\testdir\\test3.txt");
287 RemoveDirectoryA(".\\testdir\\test.txt");
288 RemoveDirectoryA(".\\testdir\\testdir2\\subdir");
289 RemoveDirectoryA(".\\testdir\\testdir2");
290 RemoveDirectoryA(".\\testdir");
295 static void test_EnumObjects(IShellFolder *iFolder)
297 IEnumIDList *iEnumList;
298 LPITEMIDLIST newPIDL, idlArr[10];
303 static const WORD iResults [5][5] =
312 #define SFGAO_testfor SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | SFGAO_CAPABILITYMASK
313 /* Don't test for SFGAO_HASSUBFOLDER since we return real state and native cached */
314 static const ULONG attrs[5] =
316 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
317 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
318 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
319 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
320 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
323 hr = IShellFolder_EnumObjects(iFolder, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &iEnumList);
324 ok(hr == S_OK, "EnumObjects failed %08x\n", hr);
326 /* This is to show that, contrary to what is said on MSDN, on IEnumIDList::Next,
327 * the filesystem shellfolders return S_OK even if less than 'celt' items are
328 * returned (in contrast to S_FALSE). We have to do it in a loop since WinXP
329 * only ever returns a single entry per call. */
330 while (IEnumIDList_Next(iEnumList, 10-i, &idlArr[i], &NumPIDLs) == S_OK)
332 ok (i == 5, "i: %d\n", i);
334 hr = IEnumIDList_Release(iEnumList);
335 ok(hr == S_OK, "IEnumIDList_Release failed %08x\n", hr);
337 /* Sort them first in case of wrong order from system */
338 for (i=0;i<5;i++) for (j=0;j<5;j++)
339 if ((SHORT)IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]) < 0)
342 idlArr[i] = idlArr[j];
346 for (i=0;i<5;i++) for (j=0;j<5;j++)
348 hr = IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]);
349 ok(hr == iResults[i][j], "Got %x expected [%d]-[%d]=%x\n", hr, i, j, iResults[i][j]);
353 for (i = 0; i < 5; i++)
356 #define SFGAO_VISTA SFGAO_DROPTARGET | SFGAO_CANLINK | SFGAO_CANCOPY
357 /* Native returns all flags no matter what we ask for */
358 flags = SFGAO_CANCOPY;
359 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
360 flags &= SFGAO_testfor;
361 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
362 ok(flags == (attrs[i]) ||
363 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR) || /* Win9x, NT4 */
364 flags == ((attrs[i] & ~SFGAO_CAPABILITYMASK) | SFGAO_VISTA), /* Vista and higher */
365 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
367 flags = SFGAO_testfor;
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 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
377 IMalloc_Free(ppM, idlArr[i]);
380 static void test_BindToObject(void)
384 IShellFolder *psfDesktop, *psfChild, *psfMyComputer, *psfSystemDir;
385 SHITEMID emptyitem = { 0, { 0 } };
386 LPITEMIDLIST pidlMyComputer, pidlSystemDir, pidlEmpty = (LPITEMIDLIST)&emptyitem;
387 WCHAR wszSystemDir[MAX_PATH];
388 char szSystemDir[MAX_PATH];
389 WCHAR wszMyComputer[] = {
390 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
391 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
393 /* The following tests shows that BindToObject should fail with E_INVALIDARG if called
394 * with an empty pidl. This is tested for Desktop, MyComputer and the FS ShellFolder
396 hr = SHGetDesktopFolder(&psfDesktop);
397 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
398 if (hr != S_OK) return;
400 hr = IShellFolder_BindToObject(psfDesktop, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
401 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
403 hr = IShellFolder_BindToObject(psfDesktop, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
404 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
406 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
407 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
409 IShellFolder_Release(psfDesktop);
413 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
414 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
415 IShellFolder_Release(psfDesktop);
416 IMalloc_Free(ppM, pidlMyComputer);
417 if (hr != S_OK) return;
419 hr = IShellFolder_BindToObject(psfMyComputer, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
420 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
424 /* this call segfaults on 98SE */
425 hr = IShellFolder_BindToObject(psfMyComputer, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
426 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
429 cChars = GetSystemDirectoryA(szSystemDir, MAX_PATH);
430 ok (cChars > 0 && cChars < MAX_PATH, "GetSystemDirectoryA failed! LastError: %u\n", GetLastError());
431 if (cChars == 0 || cChars >= MAX_PATH) {
432 IShellFolder_Release(psfMyComputer);
435 MultiByteToWideChar(CP_ACP, 0, szSystemDir, -1, wszSystemDir, MAX_PATH);
437 hr = IShellFolder_ParseDisplayName(psfMyComputer, NULL, NULL, wszSystemDir, NULL, &pidlSystemDir, NULL);
438 ok (hr == S_OK, "MyComputers's ParseDisplayName failed to parse the SystemDirectory! hr = %08x\n", hr);
440 IShellFolder_Release(psfMyComputer);
444 hr = IShellFolder_BindToObject(psfMyComputer, pidlSystemDir, NULL, &IID_IShellFolder, (LPVOID*)&psfSystemDir);
445 ok (hr == S_OK, "MyComputer failed to bind to a FileSystem ShellFolder! hr = %08x\n", hr);
446 IShellFolder_Release(psfMyComputer);
447 IMalloc_Free(ppM, pidlSystemDir);
448 if (hr != S_OK) return;
450 hr = IShellFolder_BindToObject(psfSystemDir, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
451 ok (hr == E_INVALIDARG,
452 "FileSystem ShellFolder's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
456 /* this call segfaults on 98SE */
457 hr = IShellFolder_BindToObject(psfSystemDir, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
458 ok (hr == E_INVALIDARG,
459 "FileSystem ShellFolder's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
462 IShellFolder_Release(psfSystemDir);
465 /* Based on PathAddBackslashW from dlls/shlwapi/path.c */
466 static LPWSTR myPathAddBackslashW( LPWSTR lpszPath )
470 if (!lpszPath || (iLen = lstrlenW(lpszPath)) >= MAX_PATH)
476 if (lpszPath[-1] != '\\')
485 static void test_GetDisplayName(void)
490 WCHAR wszTestFile[MAX_PATH], wszTestFile2[MAX_PATH];
491 char szTestFile[MAX_PATH], szTestDir[MAX_PATH];
494 LPSHELLFOLDER psfDesktop, psfPersonal;
496 SHITEMID emptyitem = { 0, { 0 } };
497 LPITEMIDLIST pidlTestFile, pidlEmpty = (LPITEMIDLIST)&emptyitem;
498 LPCITEMIDLIST pidlLast;
499 static const CHAR szFileName[] = "winetest.foo";
500 static const WCHAR wszFileName[] = { 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
501 static const WCHAR wszDirName[] = { 'w','i','n','e','t','e','s','t',0 };
503 /* I'm trying to figure if there is a functional difference between calling
504 * SHGetPathFromIDListW and calling GetDisplayNameOf(SHGDN_FORPARSING) after
505 * binding to the shellfolder. One thing I thought of was that perhaps
506 * SHGetPathFromIDListW would be able to get the path to a file, which does
507 * not exist anymore, while the other method wouldn't. It turns out there's
508 * no functional difference in this respect.
511 if(!pSHGetSpecialFolderPathA) {
512 win_skip("SHGetSpecialFolderPathA is not available\n");
516 /* First creating a directory in MyDocuments and a file in this directory. */
517 result = pSHGetSpecialFolderPathA(NULL, szTestDir, CSIDL_PERSONAL, FALSE);
518 ok(result, "SHGetSpecialFolderPathA failed! Last error: %u\n", GetLastError());
521 /* Use ANSI file functions so this works on Windows 9x */
522 lstrcatA(szTestDir, "\\winetest");
523 CreateDirectoryA(szTestDir, NULL);
524 attr=GetFileAttributesA(szTestDir);
525 if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY))
527 ok(0, "unable to create the '%s' directory\n", szTestDir);
531 lstrcpyA(szTestFile, szTestDir);
532 lstrcatA(szTestFile, "\\");
533 lstrcatA(szTestFile, szFileName);
534 hTestFile = CreateFileA(szTestFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
535 ok((hTestFile != INVALID_HANDLE_VALUE), "CreateFileA failed! Last error: %u\n", GetLastError());
536 if (hTestFile == INVALID_HANDLE_VALUE) return;
537 CloseHandle(hTestFile);
539 /* Getting an itemidlist for the file. */
540 hr = SHGetDesktopFolder(&psfDesktop);
541 ok(hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
542 if (hr != S_OK) return;
544 MultiByteToWideChar(CP_ACP, 0, szTestFile, -1, wszTestFile, MAX_PATH);
546 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
547 ok(hr == S_OK, "Desktop->ParseDisplayName failed! hr = %08x\n", hr);
549 IShellFolder_Release(psfDesktop);
553 pidlLast = pILFindLastID(pidlTestFile);
554 ok(pidlLast->mkid.cb >=76 ||
555 broken(pidlLast->mkid.cb == 28) || /* W2K */
556 broken(pidlLast->mkid.cb == 40), /* Win9x, WinME */
557 "Expected pidl length of at least 76, got %d.\n", pidlLast->mkid.cb);
558 if (pidlLast->mkid.cb >= 28) {
559 ok(!lstrcmpA((CHAR*)&pidlLast->mkid.abID[12], szFileName),
560 "Filename should be stored as ansi-string at this position!\n");
562 /* WinXP and up store the filenames as both ANSI and UNICODE in the pidls */
563 if (pidlLast->mkid.cb >= 76) {
564 ok(!lstrcmpW((WCHAR*)&pidlLast->mkid.abID[46], wszFileName) ||
565 (pidlLast->mkid.cb >= 94 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[64], wszFileName)) || /* Vista */
566 (pidlLast->mkid.cb >= 98 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[68], wszFileName)), /* Win7 */
567 "Filename should be stored as wchar-string at this position!\n");
570 /* It seems as if we cannot bind to regular files on windows, but only directories.
572 hr = IShellFolder_BindToObject(psfDesktop, pidlTestFile, NULL, &IID_IUnknown, (VOID**)&psfFile);
574 ok (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
575 hr == E_NOTIMPL || /* Vista */
576 broken(hr == S_OK), /* Win9x, W2K */
579 IShellFolder_Release(psfFile);
582 if (!pSHBindToParent)
584 win_skip("SHBindToParent is missing\n");
585 DeleteFileA(szTestFile);
586 RemoveDirectoryA(szTestDir);
590 /* Some tests for IShellFolder::SetNameOf */
591 if (pSHGetFolderPathAndSubDirA)
593 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
594 ok(hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
596 /* It's ok to use this fixed path. Call will fail anyway. */
597 WCHAR wszAbsoluteFilename[] = { 'C',':','\\','w','i','n','e','t','e','s','t', 0 };
598 LPITEMIDLIST pidlNew;
600 /* The pidl returned through the last parameter of SetNameOf is a simple one. */
601 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlLast, wszDirName, SHGDN_NORMAL, &pidlNew);
602 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
605 ok (((LPITEMIDLIST)((LPBYTE)pidlNew+pidlNew->mkid.cb))->mkid.cb == 0,
606 "pidl returned from SetNameOf should be simple!\n");
608 /* Passing an absolute path to SetNameOf fails. The HRESULT code indicates that SetNameOf
609 * is implemented on top of SHFileOperation in WinXP. */
610 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszAbsoluteFilename,
611 SHGDN_FORPARSING, NULL);
612 ok (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED), "SetNameOf succeeded! hr = %08x\n", hr);
614 /* Rename the file back to its original name. SetNameOf ignores the fact, that the
615 * SHGDN flags specify an absolute path. */
616 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszFileName, SHGDN_FORPARSING, NULL);
617 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
622 IShellFolder_Release(psfPersonal);
626 win_skip("Avoid needs of interaction on Win2k\n");
628 /* Deleting the file and the directory */
629 DeleteFileA(szTestFile);
630 RemoveDirectoryA(szTestDir);
632 /* SHGetPathFromIDListW still works, although the file is not present anymore. */
633 if (pSHGetPathFromIDListW)
635 result = pSHGetPathFromIDListW(pidlTestFile, wszTestFile2);
636 ok (result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
637 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "SHGetPathFromIDListW returns incorrect path!\n");
640 /* SHBindToParent fails, if called with a NULL PIDL. */
641 hr = pSHBindToParent(NULL, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
642 ok (hr != S_OK, "SHBindToParent(NULL) should fail!\n");
644 /* But it succeeds with an empty PIDL. */
645 hr = pSHBindToParent(pidlEmpty, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
646 ok (hr == S_OK, "SHBindToParent(empty PIDL) should succeed! hr = %08x\n", hr);
647 ok (pidlLast == pidlEmpty, "The last element of an empty PIDL should be the PIDL itself!\n");
649 IShellFolder_Release(psfPersonal);
651 /* Binding to the folder and querying the display name of the file also works. */
652 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
653 ok (hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
655 IShellFolder_Release(psfDesktop);
659 /* This test shows that Windows doesn't allocate a new pidlLast, but returns a pointer into
660 * pidlTestFile (In accordance with MSDN). */
661 ok (pILFindLastID(pidlTestFile) == pidlLast,
662 "SHBindToParent doesn't return the last id of the pidl param!\n");
664 hr = IShellFolder_GetDisplayNameOf(psfPersonal, pidlLast, SHGDN_FORPARSING, &strret);
665 ok (hr == S_OK, "Personal->GetDisplayNameOf failed! hr = %08x\n", hr);
667 IShellFolder_Release(psfDesktop);
668 IShellFolder_Release(psfPersonal);
674 hr = pStrRetToBufW(&strret, pidlLast, wszTestFile2, MAX_PATH);
675 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
676 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "GetDisplayNameOf returns incorrect path!\n");
679 ILFree(pidlTestFile);
680 IShellFolder_Release(psfDesktop);
681 IShellFolder_Release(psfPersonal);
684 static void test_CallForAttributes(void)
690 LPSHELLFOLDER psfDesktop;
691 LPITEMIDLIST pidlMyDocuments;
692 DWORD dwAttributes, dwCallForAttributes, dwOrigAttributes, dwOrigCallForAttributes;
693 static const WCHAR wszAttributes[] = { 'A','t','t','r','i','b','u','t','e','s',0 };
694 static const WCHAR wszCallForAttributes[] = {
695 'C','a','l','l','F','o','r','A','t','t','r','i','b','u','t','e','s',0 };
696 static const WCHAR wszMyDocumentsKey[] = {
697 'C','L','S','I','D','\\','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-',
698 '1','1','D','0','-','9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',
699 '\\','S','h','e','l','l','F','o','l','d','e','r',0 };
700 WCHAR wszMyDocuments[] = {
701 ':',':','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-','1','1','D','0','-',
702 '9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',0 };
704 /* For the root of a namespace extension, the attributes are not queried by binding
705 * to the object and calling GetAttributesOf. Instead, the attributes are read from
706 * the registry value HKCR/CLSID/{...}/ShellFolder/Attributes. This is documented on MSDN.
708 * The MyDocuments shellfolder on WinXP has a HKCR/CLSID/{...}/ShellFolder/CallForAttributes
709 * value. It seems that if the folder is queried for one of the flags set in CallForAttributes,
710 * the shell does bind to the folder object and calls GetAttributesOf. This is not documented
711 * on MSDN. This test is meant to document the observed behaviour on WinXP SP2.
713 hr = SHGetDesktopFolder(&psfDesktop);
714 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
715 if (hr != S_OK) return;
717 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyDocuments, NULL,
718 &pidlMyDocuments, NULL);
720 broken(hr == E_INVALIDARG), /* Win95, NT4 */
721 "Desktop's ParseDisplayName failed to parse MyDocuments's CLSID! hr = %08x\n", hr);
723 IShellFolder_Release(psfDesktop);
727 dwAttributes = 0xffffffff;
728 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
729 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
730 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
732 /* We need the following setup (as observed on WinXP SP2), for the tests to make sense. */
733 ok (dwAttributes & SFGAO_FILESYSTEM, "SFGAO_FILESYSTEM attribute is not set for MyDocuments!\n");
734 ok (!(dwAttributes & SFGAO_ISSLOW), "SFGAO_ISSLOW attribute is set for MyDocuments!\n");
735 ok (!(dwAttributes & SFGAO_GHOSTED), "SFGAO_GHOSTED attribute is set for MyDocuments!\n");
737 /* We don't have the MyDocuments shellfolder in wine yet, and thus we don't have the registry
738 * key. So the test will return at this point, if run on wine.
740 lResult = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszMyDocumentsKey, 0, KEY_WRITE|KEY_READ, &hKey);
741 ok (lResult == ERROR_SUCCESS ||
742 lResult == ERROR_ACCESS_DENIED,
743 "RegOpenKeyEx failed! result: %08x\n", lResult);
744 if (lResult != ERROR_SUCCESS) {
745 if (lResult == ERROR_ACCESS_DENIED)
746 skip("Not enough rights to open the registry key\n");
747 IMalloc_Free(ppM, pidlMyDocuments);
748 IShellFolder_Release(psfDesktop);
752 /* Query MyDocuments' Attributes value, to be able to restore it later. */
753 dwSize = sizeof(DWORD);
754 lResult = RegQueryValueExW(hKey, wszAttributes, NULL, NULL, (LPBYTE)&dwOrigAttributes, &dwSize);
755 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
756 if (lResult != ERROR_SUCCESS) {
758 IMalloc_Free(ppM, pidlMyDocuments);
759 IShellFolder_Release(psfDesktop);
763 /* Query MyDocuments' CallForAttributes value, to be able to restore it later. */
764 dwSize = sizeof(DWORD);
765 lResult = RegQueryValueExW(hKey, wszCallForAttributes, NULL, NULL,
766 (LPBYTE)&dwOrigCallForAttributes, &dwSize);
767 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
768 if (lResult != ERROR_SUCCESS) {
770 IMalloc_Free(ppM, pidlMyDocuments);
771 IShellFolder_Release(psfDesktop);
775 /* Define via the Attributes value that MyDocuments attributes are SFGAO_ISSLOW and
776 * SFGAO_GHOSTED and that MyDocuments should be called for the SFGAO_ISSLOW and
777 * SFGAO_FILESYSTEM attributes. */
778 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED;
779 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwAttributes, sizeof(DWORD));
780 dwCallForAttributes = SFGAO_ISSLOW|SFGAO_FILESYSTEM;
781 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
782 (LPBYTE)&dwCallForAttributes, sizeof(DWORD));
784 /* Although it is not set in CallForAttributes, the SFGAO_GHOSTED flag is reset by
785 * GetAttributesOf. It seems that once there is a single attribute queried, for which
786 * CallForAttributes is set, all flags are taken from the GetAttributesOf call and
787 * the flags in Attributes are ignored.
789 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED|SFGAO_FILESYSTEM;
790 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
791 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
792 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
794 ok (dwAttributes == SFGAO_FILESYSTEM,
795 "Desktop->GetAttributes(MyDocuments) returned unexpected attributes: %08x\n",
798 /* Restore MyDocuments' original Attributes and CallForAttributes registry values */
799 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwOrigAttributes, sizeof(DWORD));
800 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
801 (LPBYTE)&dwOrigCallForAttributes, sizeof(DWORD));
803 IMalloc_Free(ppM, pidlMyDocuments);
804 IShellFolder_Release(psfDesktop);
807 static void test_GetAttributesOf(void)
810 LPSHELLFOLDER psfDesktop, psfMyComputer;
811 SHITEMID emptyitem = { 0, { 0 } };
812 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
813 LPITEMIDLIST pidlMyComputer;
815 static const DWORD desktopFlags[] = {
817 SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSANCESTOR |
818 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
820 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_STREAM | SFGAO_FILESYSANCESTOR |
821 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
822 /* WinMe, Win9x, WinNT*/
823 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSANCESTOR |
824 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
826 static const DWORD myComputerFlags[] = {
828 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
829 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
831 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_STREAM |
832 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
833 /* WinMe, Win9x, WinNT */
834 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
835 SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
836 /* Win95, WinNT when queried directly */
837 SFGAO_CANLINK | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
838 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
840 WCHAR wszMyComputer[] = {
841 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
842 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
843 char cCurrDirA [MAX_PATH] = {0};
844 WCHAR cCurrDirW [MAX_PATH];
845 static WCHAR cTestDirW[] = {'t','e','s','t','d','i','r',0};
846 IShellFolder *IDesktopFolder, *testIShellFolder;
849 BOOL foundFlagsMatch;
851 hr = SHGetDesktopFolder(&psfDesktop);
852 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
853 if (hr != S_OK) return;
855 /* The Desktop attributes can be queried with a single empty itemidlist, .. */
856 dwFlags = 0xffffffff;
857 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, &pidlEmpty, &dwFlags);
858 ok (hr == S_OK, "Desktop->GetAttributesOf(empty pidl) failed! hr = %08x\n", hr);
859 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
860 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
862 if (desktopFlags[i] == dwFlags)
863 foundFlagsMatch = TRUE;
865 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
867 /* .. or with no itemidlist at all. */
868 dwFlags = 0xffffffff;
869 hr = IShellFolder_GetAttributesOf(psfDesktop, 0, NULL, &dwFlags);
870 ok (hr == S_OK, "Desktop->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
871 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
872 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
874 if (desktopFlags[i] == dwFlags)
875 foundFlagsMatch = TRUE;
877 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
879 /* Testing the attributes of the MyComputer shellfolder */
880 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
881 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
883 IShellFolder_Release(psfDesktop);
887 /* Windows sets the SFGAO_CANLINK flag, when MyComputer is queried via the Desktop
888 * folder object. It doesn't do this, if MyComputer is queried directly (see below).
890 dwFlags = 0xffffffff;
891 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, (LPCITEMIDLIST*)&pidlMyComputer, &dwFlags);
892 ok (hr == S_OK, "Desktop->GetAttributesOf(MyComputer) failed! hr = %08x\n", hr);
893 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
894 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
896 if ((myComputerFlags[i] | SFGAO_CANLINK) == dwFlags)
897 foundFlagsMatch = TRUE;
900 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
902 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
903 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
904 IShellFolder_Release(psfDesktop);
905 IMalloc_Free(ppM, pidlMyComputer);
906 if (hr != S_OK) return;
908 hr = IShellFolder_GetAttributesOf(psfMyComputer, 1, &pidlEmpty, &dwFlags);
910 ok (hr == E_INVALIDARG ||
911 broken(hr == S_OK), /* W2K and earlier */
912 "MyComputer->GetAttributesOf(emtpy pidl) should fail! hr = %08x\n", hr);
914 dwFlags = 0xffffffff;
915 hr = IShellFolder_GetAttributesOf(psfMyComputer, 0, NULL, &dwFlags);
916 ok (hr == S_OK, "MyComputer->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
917 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
918 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
920 if (myComputerFlags[i] == dwFlags)
921 foundFlagsMatch = TRUE;
924 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
926 IShellFolder_Release(psfMyComputer);
928 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
929 len = lstrlenA(cCurrDirA);
932 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_GetAttributesOf\n");
935 if (len > 3 && cCurrDirA[len-1] == '\\')
936 cCurrDirA[len-1] = 0;
938 /* create test directory */
939 CreateFilesFolders();
941 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
943 hr = SHGetDesktopFolder(&IDesktopFolder);
944 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
946 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
947 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
949 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
950 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
952 IMalloc_Free(ppM, newPIDL);
954 /* get relative PIDL */
955 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
956 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
958 /* test the shell attributes of the test directory using the relative PIDL */
959 dwFlags = SFGAO_FOLDER;
960 hr = IShellFolder_GetAttributesOf(testIShellFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
961 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
962 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for relative PIDL: %08x\n", dwFlags);
965 IMalloc_Free(ppM, newPIDL);
967 /* append testdirectory name to path */
968 if (cCurrDirA[len-1] == '\\')
969 cCurrDirA[len-1] = 0;
970 lstrcatA(cCurrDirA, "\\testdir");
971 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
973 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
974 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
976 /* test the shell attributes of the test directory using the absolute PIDL */
977 dwFlags = SFGAO_FOLDER;
978 hr = IShellFolder_GetAttributesOf(IDesktopFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
979 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
980 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for absolute PIDL: %08x\n", dwFlags);
983 IMalloc_Free(ppM, newPIDL);
985 IShellFolder_Release(testIShellFolder);
989 IShellFolder_Release(IDesktopFolder);
992 static void test_SHGetPathFromIDList(void)
994 SHITEMID emptyitem = { 0, { 0 } };
995 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
996 LPITEMIDLIST pidlMyComputer;
997 WCHAR wszPath[MAX_PATH], wszDesktop[MAX_PATH];
1000 LPSHELLFOLDER psfDesktop;
1001 WCHAR wszMyComputer[] = {
1002 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
1003 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
1004 WCHAR wszFileName[MAX_PATH];
1005 LPITEMIDLIST pidlTestFile;
1008 static WCHAR wszTestFile[] = {
1009 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
1010 LPITEMIDLIST pidlPrograms;
1012 if(!pSHGetPathFromIDListW || !pSHGetSpecialFolderPathW)
1014 win_skip("SHGetPathFromIDListW() or SHGetSpecialFolderPathW() is missing\n");
1018 /* Calling SHGetPathFromIDListW with no pidl should return the empty string */
1021 result = pSHGetPathFromIDListW(NULL, wszPath);
1022 ok(!result, "Expected failure\n");
1023 ok(!wszPath[0], "Expected empty string\n");
1025 /* Calling SHGetPathFromIDListW with an empty pidl should return the desktop folder's path. */
1026 result = pSHGetSpecialFolderPathW(NULL, wszDesktop, CSIDL_DESKTOP, FALSE);
1027 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOP) failed! Last error: %u\n", GetLastError());
1028 if (!result) return;
1030 /* Check if we are on Win9x */
1031 SetLastError(0xdeadbeef);
1032 lstrcmpiW(wszDesktop, wszDesktop);
1033 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1035 win_skip("Most W-calls are not implemented\n");
1039 result = pSHGetPathFromIDListW(pidlEmpty, wszPath);
1040 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1041 if (!result) return;
1042 ok(!lstrcmpiW(wszDesktop, wszPath), "SHGetPathFromIDListW didn't return desktop path for empty pidl!\n");
1044 /* MyComputer does not map to a filesystem path. SHGetPathFromIDListW should fail. */
1045 hr = SHGetDesktopFolder(&psfDesktop);
1046 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1047 if (hr != S_OK) return;
1049 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1050 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1052 IShellFolder_Release(psfDesktop);
1056 SetLastError(0xdeadbeef);
1059 result = pSHGetPathFromIDListW(pidlMyComputer, wszPath);
1060 ok (!result, "SHGetPathFromIDListW succeeded where it shouldn't!\n");
1061 ok (GetLastError()==0xdeadbeef ||
1062 GetLastError()==ERROR_SUCCESS, /* Vista and higher */
1063 "Unexpected last error from SHGetPathFromIDListW: %u\n", GetLastError());
1064 ok (!wszPath[0], "Expected empty path\n");
1066 IShellFolder_Release(psfDesktop);
1070 IMalloc_Free(ppM, pidlMyComputer);
1072 result = pSHGetSpecialFolderPathW(NULL, wszFileName, CSIDL_DESKTOPDIRECTORY, FALSE);
1073 ok(result, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1075 IShellFolder_Release(psfDesktop);
1078 myPathAddBackslashW(wszFileName);
1079 lstrcatW(wszFileName, wszTestFile);
1080 hTestFile = CreateFileW(wszFileName, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
1081 ok(hTestFile != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: %u\n", GetLastError());
1082 if (hTestFile == INVALID_HANDLE_VALUE) {
1083 IShellFolder_Release(psfDesktop);
1086 CloseHandle(hTestFile);
1088 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
1089 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse filename hr = %08x\n", hr);
1091 IShellFolder_Release(psfDesktop);
1092 DeleteFileW(wszFileName);
1093 IMalloc_Free(ppM, pidlTestFile);
1097 /* This test is to show that the Desktop shellfolder prepends the CSIDL_DESKTOPDIRECTORY
1098 * path for files placed on the desktop, if called with SHGDN_FORPARSING. */
1099 hr = IShellFolder_GetDisplayNameOf(psfDesktop, pidlTestFile, SHGDN_FORPARSING, &strret);
1100 ok (hr == S_OK, "Desktop's GetDisplayNamfOf failed! hr = %08x\n", hr);
1101 IShellFolder_Release(psfDesktop);
1102 DeleteFileW(wszFileName);
1104 IMalloc_Free(ppM, pidlTestFile);
1109 pStrRetToBufW(&strret, pidlTestFile, wszPath, MAX_PATH);
1110 ok(0 == lstrcmpW(wszFileName, wszPath),
1111 "Desktop->GetDisplayNameOf(pidlTestFile, SHGDN_FORPARSING) "
1112 "returned incorrect path for file placed on desktop\n");
1115 result = pSHGetPathFromIDListW(pidlTestFile, wszPath);
1116 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1117 IMalloc_Free(ppM, pidlTestFile);
1118 if (!result) return;
1119 ok(0 == lstrcmpW(wszFileName, wszPath), "SHGetPathFromIDListW returned incorrect path for file placed on desktop\n");
1122 /* Test if we can get the path from the start menu "program files" PIDL. */
1123 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidlPrograms);
1124 ok(hr == S_OK, "SHGetFolderLocation failed: 0x%08x\n", hr);
1126 SetLastError(0xdeadbeef);
1127 result = pSHGetPathFromIDListW(pidlPrograms, wszPath);
1128 IMalloc_Free(ppM, pidlPrograms);
1129 ok(result, "SHGetPathFromIDListW failed\n");
1132 static void test_EnumObjects_and_CompareIDs(void)
1134 ITEMIDLIST *newPIDL;
1135 IShellFolder *IDesktopFolder, *testIShellFolder;
1136 char cCurrDirA [MAX_PATH] = {0};
1137 static const CHAR cTestDirA[] = "\\testdir";
1138 WCHAR cTestDirW[MAX_PATH];
1142 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1143 len = lstrlenA(cCurrDirA);
1146 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_EnumObjects_and_CompareIDs\n");
1149 if(cCurrDirA[len-1] == '\\')
1150 cCurrDirA[len-1] = 0;
1152 lstrcatA(cCurrDirA, cTestDirA);
1153 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cTestDirW, MAX_PATH);
1155 hr = SHGetDesktopFolder(&IDesktopFolder);
1156 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1158 CreateFilesFolders();
1160 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1161 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1163 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1164 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1166 test_EnumObjects(testIShellFolder);
1168 IShellFolder_Release(testIShellFolder);
1172 IMalloc_Free(ppM, newPIDL);
1174 IShellFolder_Release(IDesktopFolder);
1177 /* A simple implementation of an IPropertyBag, which returns fixed values for
1178 * 'Target' and 'Attributes' properties.
1180 static HRESULT WINAPI InitPropertyBag_IPropertyBag_QueryInterface(IPropertyBag *iface, REFIID riid,
1184 return E_INVALIDARG;
1186 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPropertyBag, riid)) {
1189 ok (FALSE, "InitPropertyBag asked for unknown interface!\n");
1190 return E_NOINTERFACE;
1193 IPropertyBag_AddRef(iface);
1197 static ULONG WINAPI InitPropertyBag_IPropertyBag_AddRef(IPropertyBag *iface) {
1201 static ULONG WINAPI InitPropertyBag_IPropertyBag_Release(IPropertyBag *iface) {
1205 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Read(IPropertyBag *iface, LPCOLESTR pszPropName,
1206 VARIANT *pVar, IErrorLog *pErrorLog)
1208 static const WCHAR wszTargetSpecialFolder[] = {
1209 'T','a','r','g','e','t','S','p','e','c','i','a','l','F','o','l','d','e','r',0 };
1210 static const WCHAR wszTarget[] = {
1211 'T','a','r','g','e','t',0 };
1212 static const WCHAR wszAttributes[] = {
1213 'A','t','t','r','i','b','u','t','e','s',0 };
1214 static const WCHAR wszResolveLinkFlags[] = {
1215 'R','e','s','o','l','v','e','L','i','n','k','F','l','a','g','s',0 };
1216 static const WCHAR wszTargetKnownFolder[] = {
1217 'T','a','r','g','e','t','K','n','o','w','n','F','o','l','d','e','r',0 };
1218 static const WCHAR wszCLSID[] = {
1219 'C','L','S','I','D',0 };
1221 if (!lstrcmpW(pszPropName, wszTargetSpecialFolder)) {
1222 ok(V_VT(pVar) == VT_I4 ||
1223 broken(V_VT(pVar) == VT_BSTR), /* Win2k */
1224 "Wrong variant type for 'TargetSpecialFolder' property!\n");
1225 return E_INVALIDARG;
1228 if (!lstrcmpW(pszPropName, wszResolveLinkFlags))
1230 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'ResolveLinkFlags' property!\n");
1231 return E_INVALIDARG;
1234 if (!lstrcmpW(pszPropName, wszTarget)) {
1235 WCHAR wszPath[MAX_PATH];
1238 ok(V_VT(pVar) == VT_BSTR ||
1239 broken(V_VT(pVar) == VT_EMPTY), /* Win2k */
1240 "Wrong variant type for 'Target' property!\n");
1241 if (V_VT(pVar) != VT_BSTR) return E_INVALIDARG;
1243 result = pSHGetSpecialFolderPathW(NULL, wszPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1244 ok(result, "SHGetSpecialFolderPathW(DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1245 if (!result) return E_INVALIDARG;
1247 V_BSTR(pVar) = SysAllocString(wszPath);
1251 if (!lstrcmpW(pszPropName, wszAttributes)) {
1252 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'Attributes' property!\n");
1253 if (V_VT(pVar) != VT_UI4) return E_INVALIDARG;
1254 V_UI4(pVar) = SFGAO_FOLDER|SFGAO_HASSUBFOLDER|SFGAO_FILESYSANCESTOR|
1255 SFGAO_CANRENAME|SFGAO_FILESYSTEM;
1259 if (!lstrcmpW(pszPropName, wszTargetKnownFolder)) {
1260 ok(V_VT(pVar) == VT_BSTR, "Wrong variant type for 'TargetKnownFolder' property!\n");
1262 return E_INVALIDARG;
1265 if (!lstrcmpW(pszPropName, wszCLSID)) {
1266 ok(V_VT(pVar) == VT_EMPTY, "Wrong variant type for 'CLSID' property!\n");
1268 return E_INVALIDARG;
1271 ok(FALSE, "PropertyBag was asked for unknown property %s (vt=%d)!\n", wine_dbgstr_w(pszPropName), V_VT(pVar));
1272 return E_INVALIDARG;
1275 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Write(IPropertyBag *iface, LPCOLESTR pszPropName,
1278 ok(FALSE, "Unexpected call to IPropertyBag_Write\n");
1282 static const IPropertyBagVtbl InitPropertyBag_IPropertyBagVtbl = {
1283 InitPropertyBag_IPropertyBag_QueryInterface,
1284 InitPropertyBag_IPropertyBag_AddRef,
1285 InitPropertyBag_IPropertyBag_Release,
1286 InitPropertyBag_IPropertyBag_Read,
1287 InitPropertyBag_IPropertyBag_Write
1290 static struct IPropertyBag InitPropertyBag = {
1291 &InitPropertyBag_IPropertyBagVtbl
1294 static void test_FolderShortcut(void) {
1295 IPersistPropertyBag *pPersistPropertyBag;
1296 IShellFolder *pShellFolder, *pDesktopFolder;
1297 IPersistFolder3 *pPersistFolder3;
1300 WCHAR wszDesktopPath[MAX_PATH], wszBuffer[MAX_PATH];
1303 LPITEMIDLIST pidlCurrentFolder, pidlWineTestFolder, pidlSubFolder;
1305 WCHAR wszWineTestFolder[] = {
1306 ':',':','{','9','B','3','5','2','E','B','F','-','2','7','6','5','-','4','5','C','1','-',
1307 'B','4','C','6','-','8','5','C','C','7','F','7','A','B','C','6','4','}',0 };
1308 WCHAR wszShellExtKey[] = { 'S','o','f','t','w','a','r','e','\\',
1309 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
1310 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1311 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
1312 'N','a','m','e','S','p','a','c','e','\\',
1313 '{','9','b','3','5','2','e','b','f','-','2','7','6','5','-','4','5','c','1','-',
1314 'b','4','c','6','-','8','5','c','c','7','f','7','a','b','c','6','4','}',0 };
1316 WCHAR wszSomeSubFolder[] = { 'S','u','b','F','o','l','d','e','r', 0};
1317 static const GUID CLSID_UnixDosFolder =
1318 {0x9d20aae8, 0x0625, 0x44b0, {0x9c, 0xa7, 0x71, 0x88, 0x9c, 0x22, 0x54, 0xd9}};
1320 if (!pSHGetSpecialFolderPathW || !pStrRetToBufW) {
1321 win_skip("SHGetSpecialFolderPathW and/or StrRetToBufW are not available\n");
1325 if (!pSHGetFolderPathAndSubDirA)
1327 win_skip("FolderShortcut test doesn't work on Win2k\n");
1331 /* These tests basically show, that CLSID_FolderShortcuts are initialized
1332 * via their IPersistPropertyBag interface. And that the target folder
1333 * is taken from the IPropertyBag's 'Target' property.
1335 hr = CoCreateInstance(&CLSID_FolderShortcut, NULL, CLSCTX_INPROC_SERVER,
1336 &IID_IPersistPropertyBag, (LPVOID*)&pPersistPropertyBag);
1337 if (hr == REGDB_E_CLASSNOTREG) {
1338 win_skip("CLSID_FolderShortcut is not implemented\n");
1341 ok (hr == S_OK, "CoCreateInstance failed! hr = 0x%08x\n", hr);
1342 if (hr != S_OK) return;
1344 hr = IPersistPropertyBag_Load(pPersistPropertyBag, &InitPropertyBag, NULL);
1345 ok(hr == S_OK, "IPersistPropertyBag_Load failed! hr = %08x\n", hr);
1347 IPersistPropertyBag_Release(pPersistPropertyBag);
1351 hr = IPersistPropertyBag_QueryInterface(pPersistPropertyBag, &IID_IShellFolder,
1352 (LPVOID*)&pShellFolder);
1353 IPersistPropertyBag_Release(pPersistPropertyBag);
1354 ok(hr == S_OK, "IPersistPropertyBag_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1355 if (hr != S_OK) return;
1357 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1358 ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1360 IShellFolder_Release(pShellFolder);
1364 result = pSHGetSpecialFolderPathW(NULL, wszDesktopPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1365 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1366 if (!result) return;
1368 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1369 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1371 hr = IShellFolder_QueryInterface(pShellFolder, &IID_IPersistFolder3, (LPVOID*)&pPersistFolder3);
1372 IShellFolder_Release(pShellFolder);
1373 ok(hr == S_OK, "IShellFolder_QueryInterface(IID_IPersistFolder3 failed! hr = 0x%08x\n", hr);
1374 if (hr != S_OK) return;
1376 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1377 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1378 ok(IsEqualCLSID(&clsid, &CLSID_FolderShortcut), "Unexpected CLSID!\n");
1380 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1381 todo_wine ok(hr == S_FALSE, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1382 ok(!pidlCurrentFolder, "IPersistFolder3_GetCurFolder should return a NULL pidl!\n");
1384 /* For FolderShortcut objects, the Initialize method initialized the folder's position in the
1385 * shell namespace. The target folder, read from the property bag above, remains untouched.
1386 * The following tests show this: The itemidlist for some imaginary shellfolder object
1387 * is created and the FolderShortcut is initialized with it. GetCurFolder now returns this
1388 * itemidlist, but GetDisplayNameOf still returns the path from above.
1390 hr = SHGetDesktopFolder(&pDesktopFolder);
1391 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1392 if (hr != S_OK) return;
1394 /* Temporarily register WineTestFolder as a shell namespace extension at the Desktop.
1395 * Otherwise ParseDisplayName fails on WinXP with E_INVALIDARG */
1396 RegCreateKeyW(HKEY_CURRENT_USER, wszShellExtKey, &hShellExtKey);
1397 RegCloseKey(hShellExtKey);
1398 hr = IShellFolder_ParseDisplayName(pDesktopFolder, NULL, NULL, wszWineTestFolder, NULL,
1399 &pidlWineTestFolder, NULL);
1400 RegDeleteKeyW(HKEY_CURRENT_USER, wszShellExtKey);
1401 IShellFolder_Release(pDesktopFolder);
1402 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1403 if (hr != S_OK) return;
1405 hr = IPersistFolder3_Initialize(pPersistFolder3, pidlWineTestFolder);
1406 ok (hr == S_OK, "IPersistFolder3::Initialize failed! hr = %08x\n", hr);
1408 IPersistFolder3_Release(pPersistFolder3);
1409 pILFree(pidlWineTestFolder);
1413 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1414 ok(hr == S_OK, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1415 ok(pILIsEqual(pidlCurrentFolder, pidlWineTestFolder),
1416 "IPersistFolder3_GetCurFolder should return pidlWineTestFolder!\n");
1417 pILFree(pidlCurrentFolder);
1418 pILFree(pidlWineTestFolder);
1420 hr = IPersistFolder3_QueryInterface(pPersistFolder3, &IID_IShellFolder, (LPVOID*)&pShellFolder);
1421 IPersistFolder3_Release(pPersistFolder3);
1422 ok(hr == S_OK, "IPersistFolder3_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1423 if (hr != S_OK) return;
1425 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1426 ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1428 IShellFolder_Release(pShellFolder);
1432 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1433 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1435 /* Next few lines are meant to show that children of FolderShortcuts are not FolderShortcuts,
1436 * but ShellFSFolders. */
1437 myPathAddBackslashW(wszDesktopPath);
1438 lstrcatW(wszDesktopPath, wszSomeSubFolder);
1439 if (!CreateDirectoryW(wszDesktopPath, NULL)) {
1440 IShellFolder_Release(pShellFolder);
1444 hr = IShellFolder_ParseDisplayName(pShellFolder, NULL, NULL, wszSomeSubFolder, NULL,
1445 &pidlSubFolder, NULL);
1446 RemoveDirectoryW(wszDesktopPath);
1447 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1449 IShellFolder_Release(pShellFolder);
1453 hr = IShellFolder_BindToObject(pShellFolder, pidlSubFolder, NULL, &IID_IPersistFolder3,
1454 (LPVOID*)&pPersistFolder3);
1455 IShellFolder_Release(pShellFolder);
1456 pILFree(pidlSubFolder);
1457 ok (hr == S_OK, "IShellFolder::BindToObject failed! hr = %08x\n", hr);
1461 /* On windows, we expect CLSID_ShellFSFolder. On wine we relax this constraint
1462 * a little bit and also allow CLSID_UnixDosFolder. */
1463 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1464 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1465 ok(IsEqualCLSID(&clsid, &CLSID_ShellFSFolder) || IsEqualCLSID(&clsid, &CLSID_UnixDosFolder),
1466 "IPersistFolder3::GetClassID returned unexpected CLSID!\n");
1468 IPersistFolder3_Release(pPersistFolder3);
1471 #include "pshpack1.h"
1472 struct FileStructA {
1476 WORD uFileDate; /* In our current implementation this is */
1477 WORD uFileTime; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastWriteTime) */
1482 struct FileStructW {
1483 WORD cbLen; /* Length of this element. */
1484 BYTE abFooBar1[6]; /* Beyond any recognition. */
1485 WORD uDate; /* FileTimeToDosDate(WIN32_FIND_DATA->ftCreationTime)? */
1486 WORD uTime; /* (this is currently speculation) */
1487 WORD uDate2; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastAccessTime)? */
1488 WORD uTime2; /* (this is currently speculation) */
1489 BYTE abFooBar2[4]; /* Beyond any recognition. */
1490 WCHAR wszName[1]; /* The long filename in unicode. */
1491 /* Just for documentation: Right after the unicode string: */
1492 WORD cbOffset; /* FileStructW's offset from the beginning of the SHITMEID.
1493 * SHITEMID->cb == uOffset + cbLen */
1495 #include "poppack.h"
1497 static void test_ITEMIDLIST_format(void) {
1498 WCHAR wszPersonal[MAX_PATH];
1499 LPSHELLFOLDER psfDesktop, psfPersonal;
1500 LPITEMIDLIST pidlPersonal, pidlFile;
1504 WCHAR wszFile[3][17] = { { 'e','v','e','n','_',0 }, { 'o','d','d','_',0 },
1505 { 'l','o','n','g','e','r','_','t','h','a','n','.','8','_','3',0 } };
1508 if (!pSHGetSpecialFolderPathW) return;
1510 bResult = pSHGetSpecialFolderPathW(NULL, wszPersonal, CSIDL_PERSONAL, FALSE);
1511 ok(bResult, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1512 if (!bResult) return;
1514 SetLastError(0xdeadbeef);
1515 bResult = SetCurrentDirectoryW(wszPersonal);
1516 if (!bResult && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
1517 win_skip("Most W-calls are not implemented\n");
1520 ok(bResult, "SetCurrentDirectory failed! Last error: %u\n", GetLastError());
1521 if (!bResult) return;
1523 hr = SHGetDesktopFolder(&psfDesktop);
1524 ok(hr == S_OK, "SHGetDesktopFolder failed! hr: %08x\n", hr);
1525 if (hr != S_OK) return;
1527 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszPersonal, NULL, &pidlPersonal, NULL);
1528 ok(hr == S_OK, "psfDesktop->ParseDisplayName failed! hr = %08x\n", hr);
1530 IShellFolder_Release(psfDesktop);
1534 hr = IShellFolder_BindToObject(psfDesktop, pidlPersonal, NULL, &IID_IShellFolder,
1535 (LPVOID*)&psfPersonal);
1536 IShellFolder_Release(psfDesktop);
1537 pILFree(pidlPersonal);
1538 ok(hr == S_OK, "psfDesktop->BindToObject failed! hr = %08x\n", hr);
1539 if (hr != S_OK) return;
1541 for (i=0; i<3; i++) {
1542 CHAR szFile[MAX_PATH];
1543 struct FileStructA *pFileStructA;
1546 WideCharToMultiByte(CP_ACP, 0, wszFile[i], -1, szFile, MAX_PATH, NULL, NULL);
1548 hFile = CreateFileW(wszFile[i], GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_FLAG_WRITE_THROUGH, NULL);
1549 ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed! (%u)\n", GetLastError());
1550 if (hFile == INVALID_HANDLE_VALUE) {
1551 IShellFolder_Release(psfPersonal);
1556 hr = IShellFolder_ParseDisplayName(psfPersonal, NULL, NULL, wszFile[i], NULL, &pidlFile, NULL);
1557 DeleteFileW(wszFile[i]);
1558 ok(hr == S_OK, "psfPersonal->ParseDisplayName failed! hr: %08x\n", hr);
1560 IShellFolder_Release(psfPersonal);
1564 pFileStructA = (struct FileStructA *)pidlFile->mkid.abID;
1565 ok(pFileStructA->type == 0x32, "PIDLTYPE should be 0x32!\n");
1566 ok(pFileStructA->dummy == 0x00, "Dummy Byte should be 0x00!\n");
1567 ok(pFileStructA->dwFileSize == 0, "Filesize should be zero!\n");
1569 if (i < 2) /* First two file names are already in valid 8.3 format */
1570 ok(!strcmp(szFile, (CHAR*)&pidlFile->mkid.abID[12]), "Wrong file name!\n");
1572 /* WinXP stores a derived 8.3 dos name (LONGER~1.8_3) here. We probably
1573 * can't implement this correctly, since unix filesystems don't support
1574 * this nasty short/long filename stuff. So we'll probably stay with our
1575 * current habbit of storing the long filename here, which seems to work
1578 ok(pidlFile->mkid.abID[18] == '~' ||
1579 broken(pidlFile->mkid.abID[34] == '~'), /* Win2k */
1580 "Should be derived 8.3 name!\n");
1582 if (i == 0) /* First file name has an even number of chars. No need for alignment. */
1583 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] != '\0' ||
1584 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1), /* Win2k */
1585 "Alignment byte, where there shouldn't be!\n");
1587 if (i == 1) /* Second file name has an uneven number of chars => alignment byte */
1588 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] == '\0',
1589 "There should be an alignment byte, but isn't!\n");
1591 /* The offset of the FileStructW member is stored as a WORD at the end of the pidl. */
1592 cbOffset = *(WORD*)(((LPBYTE)pidlFile)+pidlFile->mkid.cb-sizeof(WORD));
1593 ok ((cbOffset >= sizeof(struct FileStructA) &&
1594 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW)) ||
1595 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1) || /* Win2k on short names */
1596 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 12 + 1), /* Win2k on long names */
1597 "Wrong offset value (%d) stored at the end of the PIDL\n", cbOffset);
1599 if (cbOffset >= sizeof(struct FileStructA) &&
1600 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW))
1602 struct FileStructW *pFileStructW = (struct FileStructW *)(((LPBYTE)pidlFile)+cbOffset);
1604 ok(pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen,
1605 "FileStructW's offset and length should add up to the PIDL's length!\n");
1607 if (pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen) {
1608 /* Since we just created the file, time of creation,
1609 * time of last access and time of last write access just be the same.
1610 * These tests seem to fail sometimes (on WinXP), if the test is run again shortly
1611 * after the first run. I do remember something with NTFS keeping the creation time
1612 * if a file is deleted and then created again within a couple of seconds or so.
1613 * Might be the reason. */
1614 ok (pFileStructA->uFileDate == pFileStructW->uDate &&
1615 pFileStructA->uFileTime == pFileStructW->uTime,
1616 "Last write time should match creation time!\n");
1618 /* On FAT filesystems the last access time is midnight
1619 local time, so the values of uDate2 and uTime2 will
1620 depend on the local timezone. If the times are exactly
1621 equal then the dates should be identical for both FAT
1622 and NTFS as no timezone is more than 1 day away from UTC.
1624 if (pFileStructA->uFileTime == pFileStructW->uTime2)
1626 ok (pFileStructA->uFileDate == pFileStructW->uDate2,
1627 "Last write date and time should match last access date and time!\n");
1631 /* Filesystem may be FAT. Check date within 1 day
1632 and seconds are zero. */
1633 trace ("Filesystem may be FAT. Performing less strict atime test.\n");
1634 ok ((pFileStructW->uTime2 & 0x1F) == 0,
1635 "Last access time on FAT filesystems should have zero seconds.\n");
1636 /* TODO: Perform check for date being within one day.*/
1639 ok (!lstrcmpW(wszFile[i], pFileStructW->wszName) ||
1640 !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 22)) || /* Vista */
1641 !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 26)), /* Win7 */
1642 "The filename should be stored in unicode at this position!\n");
1649 IShellFolder_Release(psfPersonal);
1652 static void test_SHGetFolderPathAndSubDirA(void)
1658 static char wine[] = "wine";
1659 static char winetemp[] = "wine\\temp";
1660 static char appdata[MAX_PATH];
1661 static char testpath[MAX_PATH];
1662 static char toolongpath[MAX_PATH+1];
1664 if(!pSHGetFolderPathAndSubDirA)
1666 win_skip("SHGetFolderPathAndSubDirA not present!\n");
1670 if(!pSHGetFolderPathA) {
1671 win_skip("SHGetFolderPathA not present!\n");
1674 if(FAILED(pSHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdata)))
1676 win_skip("SHGetFolderPathA failed for CSIDL_LOCAL_APPDATA!\n");
1680 sprintf(testpath, "%s\\%s", appdata, winetemp);
1681 delret = RemoveDirectoryA(testpath);
1682 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) ) {
1683 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1687 sprintf(testpath, "%s\\%s", appdata, wine);
1688 delret = RemoveDirectoryA(testpath);
1689 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) && (ERROR_FILE_NOT_FOUND != GetLastError())) {
1690 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1694 /* test invalid second parameter */
1695 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | 0xff, NULL, SHGFP_TYPE_CURRENT, wine, testpath);
1696 ok(E_INVALIDARG == ret, "expected E_INVALIDARG, got %x\n", ret);
1698 /* test fourth parameter */
1699 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, 2, winetemp, testpath);
1701 case S_OK: /* winvista */
1702 ok(!strncmp(appdata, testpath, strlen(appdata)),
1703 "expected %s to start with %s\n", testpath, appdata);
1704 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1705 "expected %s to end with %s\n", testpath, winetemp);
1707 case E_INVALIDARG: /* winxp, win2k3 */
1710 ok(0, "expected S_OK or E_INVALIDARG, got %x\n", ret);
1713 /* test fifth parameter */
1715 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, NULL, testpath);
1716 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1717 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1720 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "", testpath);
1721 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1722 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1725 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "\\", testpath);
1726 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1727 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1729 for(i=0; i< MAX_PATH; i++)
1730 toolongpath[i] = '0' + i % 10;
1731 toolongpath[MAX_PATH] = '\0';
1732 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, toolongpath, testpath);
1733 ok(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) == ret,
1734 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), ret);
1737 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wine, NULL);
1738 ok((S_OK == ret) || (E_INVALIDARG == ret), "expected S_OK or E_INVALIDARG, got %x\n", ret);
1740 /* test a not existing path */
1742 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
1743 ok(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == ret,
1744 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), ret);
1746 /* create a directory inside a not existing directory */
1748 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_CREATE | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
1749 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1750 ok(!strncmp(appdata, testpath, strlen(appdata)),
1751 "expected %s to start with %s\n", testpath, appdata);
1752 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1753 "expected %s to end with %s\n", testpath, winetemp);
1754 dwret = GetFileAttributes(testpath);
1755 ok(FILE_ATTRIBUTE_DIRECTORY | dwret, "expected %x to contain FILE_ATTRIBUTE_DIRECTORY\n", dwret);
1758 sprintf(testpath, "%s\\%s", appdata, winetemp);
1759 RemoveDirectoryA(testpath);
1760 sprintf(testpath, "%s\\%s", appdata, wine);
1761 RemoveDirectoryA(testpath);
1764 static void test_LocalizedNames(void)
1766 static char cCurrDirA[MAX_PATH];
1767 WCHAR cCurrDirW[MAX_PATH], tempbufW[25];
1768 IShellFolder *IDesktopFolder, *testIShellFolder;
1769 ITEMIDLIST *newPIDL;
1772 static char resourcefile[MAX_PATH];
1777 static const char desktopini_contents1[] =
1778 "[.ShellClassInfo]\r\n"
1779 "LocalizedResourceName=@";
1780 static const char desktopini_contents2[] =
1782 static WCHAR foldernameW[] = {'t','e','s','t','f','o','l','d','e','r',0};
1783 static const WCHAR folderdisplayW[] = {'F','o','l','d','e','r',' ','N','a','m','e',' ','R','e','s','o','u','r','c','e',0};
1785 /* create folder with desktop.ini and localized name in GetModuleFileNameA(NULL) */
1786 CreateDirectoryA(".\\testfolder", NULL);
1788 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")|FILE_ATTRIBUTE_SYSTEM);
1790 GetModuleFileNameA(NULL, resourcefile, MAX_PATH);
1792 file = CreateFileA(".\\testfolder\\desktop.ini", GENERIC_WRITE, 0, NULL,
1793 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1794 ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %i\n", GetLastError());
1795 ok(WriteFile(file, desktopini_contents1, strlen(desktopini_contents1), &res, NULL) &&
1796 WriteFile(file, resourcefile, strlen(resourcefile), &res, NULL) &&
1797 WriteFile(file, desktopini_contents2, strlen(desktopini_contents2), &res, NULL),
1798 "WriteFile failed %i\n", GetLastError());
1801 /* get IShellFolder for parent */
1802 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1803 len = lstrlenA(cCurrDirA);
1806 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_LocalizedNames\n");
1809 if(cCurrDirA[len-1] == '\\')
1810 cCurrDirA[len-1] = 0;
1812 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1814 hr = SHGetDesktopFolder(&IDesktopFolder);
1815 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1817 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1818 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1820 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1821 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1823 IMalloc_Free(ppM, newPIDL);
1825 /* windows reads the display name from the resource */
1826 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, foldernameW, NULL, &newPIDL, 0);
1827 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1829 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER, &strret);
1830 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1832 if (hr == S_OK && pStrRetToBufW)
1834 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1835 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1837 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
1838 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
1839 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1842 /* editing name is also read from the resource */
1843 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FOREDITING, &strret);
1844 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1846 if (hr == S_OK && pStrRetToBufW)
1848 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1849 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1851 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
1852 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
1853 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1856 /* parsing name is unchanged */
1857 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FORPARSING, &strret);
1858 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1860 if (hr == S_OK && pStrRetToBufW)
1862 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1863 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1864 ok (!lstrcmpiW(tempbufW, foldernameW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1867 IShellFolder_Release(IDesktopFolder);
1868 IShellFolder_Release(testIShellFolder);
1870 IMalloc_Free(ppM, newPIDL);
1873 DeleteFileA(".\\testfolder\\desktop.ini");
1874 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")&~FILE_ATTRIBUTE_SYSTEM);
1875 RemoveDirectoryA(".\\testfolder");
1878 static void test_SHCreateShellItem(void)
1880 IShellItem *shellitem, *shellitem2;
1881 IPersistIDList *persistidl;
1882 LPITEMIDLIST pidl_cwd=NULL, pidl_testfile, pidl_abstestfile, pidl_test;
1884 char curdirA[MAX_PATH];
1885 WCHAR curdirW[MAX_PATH];
1886 WCHAR fnbufW[MAX_PATH];
1887 IShellFolder *desktopfolder=NULL, *currentfolder=NULL;
1888 static WCHAR testfileW[] = {'t','e','s','t','f','i','l','e',0};
1890 GetCurrentDirectoryA(MAX_PATH, curdirA);
1892 if (!pSHCreateShellItem)
1894 win_skip("SHCreateShellItem isn't available\n");
1898 if (!lstrlenA(curdirA))
1900 win_skip("GetCurrentDirectoryA returned empty string, skipping test_SHCreateShellItem\n");
1904 MultiByteToWideChar(CP_ACP, 0, curdirA, -1, curdirW, MAX_PATH);
1906 ret = SHGetDesktopFolder(&desktopfolder);
1907 ok(SUCCEEDED(ret), "SHGetShellFolder returned %x\n", ret);
1909 ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
1910 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
1912 ret = IShellFolder_BindToObject(desktopfolder, pidl_cwd, NULL, &IID_IShellFolder, (void**)¤tfolder);
1913 ok(SUCCEEDED(ret), "BindToObject returned %x\n", ret);
1915 CreateTestFile(".\\testfile");
1917 ret = IShellFolder_ParseDisplayName(currentfolder, NULL, NULL, testfileW, NULL, &pidl_testfile, NULL);
1918 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
1920 pidl_abstestfile = pILCombine(pidl_cwd, pidl_testfile);
1922 ret = pSHCreateShellItem(NULL, NULL, NULL, &shellitem);
1923 ok(ret == E_INVALIDARG, "SHCreateShellItem returned %x\n", ret);
1925 if (0) /* crashes on Windows XP */
1927 pSHCreateShellItem(NULL, NULL, pidl_cwd, NULL);
1928 pSHCreateShellItem(pidl_cwd, NULL, NULL, &shellitem);
1929 pSHCreateShellItem(NULL, currentfolder, NULL, &shellitem);
1930 pSHCreateShellItem(pidl_cwd, currentfolder, NULL, &shellitem);
1933 ret = pSHCreateShellItem(NULL, NULL, pidl_cwd, &shellitem);
1934 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
1937 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
1938 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1941 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1942 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1945 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
1948 IPersistIDList_Release(persistidl);
1950 IShellItem_Release(shellitem);
1953 ret = pSHCreateShellItem(pidl_cwd, NULL, pidl_testfile, &shellitem);
1954 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
1957 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
1958 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1961 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1962 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1965 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
1968 IPersistIDList_Release(persistidl);
1971 ret = IShellItem_GetParent(shellitem, &shellitem2);
1972 ok(SUCCEEDED(ret), "GetParent returned %x\n", ret);
1975 ret = IShellItem_QueryInterface(shellitem2, &IID_IPersistIDList, (void**)&persistidl);
1976 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1979 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1980 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1983 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
1986 IPersistIDList_Release(persistidl);
1988 IShellItem_Release(shellitem2);
1991 IShellItem_Release(shellitem);
1994 ret = pSHCreateShellItem(NULL, currentfolder, pidl_testfile, &shellitem);
1995 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
1998 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
1999 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2002 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2003 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2006 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2009 IPersistIDList_Release(persistidl);
2011 IShellItem_Release(shellitem);
2014 /* if a parent pidl and shellfolder are specified, the shellfolder is ignored */
2015 ret = pSHCreateShellItem(pidl_cwd, desktopfolder, pidl_testfile, &shellitem);
2016 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2019 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2020 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2023 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2024 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2027 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2030 IPersistIDList_Release(persistidl);
2032 IShellItem_Release(shellitem);
2035 ret = pSHCreateShellItem(NULL, desktopfolder, pidl_testfile, &shellitem);
2036 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2039 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2040 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2043 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2044 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2047 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2050 IPersistIDList_Release(persistidl);
2052 IShellItem_Release(shellitem);
2055 /* SHCreateItemFromParsingName */
2056 if(pSHCreateItemFromParsingName)
2060 /* Crashes under windows 7 */
2061 ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, NULL);
2064 shellitem = (void*)0xdeadbeef;
2065 ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, (void**)&shellitem);
2066 ok(ret == E_INVALIDARG, "SHCreateItemFromParsingName returned %x\n", ret);
2067 ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2069 ret = pSHCreateItemFromParsingName(testfileW, NULL, &IID_IShellItem, (void**)&shellitem);
2070 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
2071 "SHCreateItemFromParsingName returned %x\n", ret);
2072 if(SUCCEEDED(ret)) IShellItem_Release(shellitem);
2074 lstrcpyW(fnbufW, curdirW);
2075 myPathAddBackslashW(fnbufW);
2076 lstrcatW(fnbufW, testfileW);
2078 ret = pSHCreateItemFromParsingName(fnbufW, NULL, &IID_IShellItem, (void**)&shellitem);
2079 ok(ret == S_OK, "SHCreateItemFromParsingName returned %x\n", ret);
2083 ret = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &tmp_fname);
2084 ok(ret == S_OK, "GetDisplayName returned %x\n", ret);
2087 ok(!lstrcmpW(fnbufW, tmp_fname), "strings not equal\n");
2088 CoTaskMemFree(tmp_fname);
2090 IShellItem_Release(shellitem);
2094 win_skip("No SHCreateItemFromParsingName\n");
2097 /* SHCreateItemFromIDList */
2098 if(pSHCreateItemFromIDList)
2102 /* Crashes under win7 */
2103 ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, NULL);
2106 ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, (void**)&shellitem);
2107 ok(ret == E_INVALIDARG, "SHCreateItemFromIDList returned %x\n", ret);
2109 ret = pSHCreateItemFromIDList(pidl_cwd, &IID_IShellItem, (void**)&shellitem);
2110 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2113 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2114 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2117 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2118 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2121 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2124 IPersistIDList_Release(persistidl);
2126 IShellItem_Release(shellitem);
2129 ret = pSHCreateItemFromIDList(pidl_testfile, &IID_IShellItem, (void**)&shellitem);
2130 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2133 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2134 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2137 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2138 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2141 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2144 IPersistIDList_Release(persistidl);
2146 IShellItem_Release(shellitem);
2150 win_skip("No SHCreateItemFromIDList\n");
2152 DeleteFileA(".\\testfile");
2153 pILFree(pidl_abstestfile);
2154 pILFree(pidl_testfile);
2156 IShellFolder_Release(currentfolder);
2157 IShellFolder_Release(desktopfolder);
2160 static void test_SHGetNameFromIDList(void)
2162 IShellItem *shellitem;
2167 static const DWORD flags[] = {
2168 SIGDN_NORMALDISPLAY, SIGDN_PARENTRELATIVEPARSING,
2169 SIGDN_DESKTOPABSOLUTEPARSING,SIGDN_PARENTRELATIVEEDITING,
2170 SIGDN_DESKTOPABSOLUTEEDITING, /*SIGDN_FILESYSPATH, SIGDN_URL, */
2171 SIGDN_PARENTRELATIVEFORADDRESSBAR,SIGDN_PARENTRELATIVE, -1234};
2173 if(!pSHGetNameFromIDList)
2175 win_skip("SHGetNameFromIDList missing.\n");
2179 /* These should be available on any platform that passed the above test. */
2180 ok(pSHCreateShellItem != NULL, "SHCreateShellItem missing.\n");
2181 ok(pSHBindToParent != NULL, "SHBindToParent missing.\n");
2182 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
2183 ok(pStrRetToBufW != NULL, "StrRetToBufW missing.\n");
2187 /* Crashes under win7 */
2188 hres = pSHGetNameFromIDList(NULL, 0, NULL);
2191 hres = pSHGetNameFromIDList(NULL, 0, &name_string);
2192 ok(hres == E_INVALIDARG, "Got 0x%08x\n", hres);
2194 /* Test the desktop */
2195 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
2196 ok(hres == S_OK, "Got 0x%08x\n", hres);
2197 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2198 ok(hres == S_OK, "Got 0x%08x\n", hres);
2201 WCHAR *nameSI, *nameSH;
2202 WCHAR buf[MAX_PATH];
2203 HRESULT hrSI, hrSH, hrSF;
2208 SHGetDesktopFolder(&psf);
2209 for(i = 0; flags[i] != -1234; i++)
2211 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2212 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2213 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2214 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2215 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2216 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2218 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2219 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2223 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2225 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2227 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2229 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2230 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2232 IShellFolder_Release(psf);
2234 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2235 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2236 res = SHGetPathFromIDListW(pidl, buf);
2237 ok(res == TRUE, "Got %d\n", res);
2238 if(SUCCEEDED(hrSI) && res)
2239 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2240 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2242 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2243 todo_wine ok(hres == S_OK, "Got 0x%08x\n", hres);
2244 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2246 IShellItem_Release(shellitem);
2250 /* Test the control panel */
2251 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_CONTROLS, &pidl);
2252 ok(hres == S_OK, "Got 0x%08x\n", hres);
2253 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2254 ok(hres == S_OK, "Got 0x%08x\n", hres);
2257 WCHAR *nameSI, *nameSH;
2258 WCHAR buf[MAX_PATH];
2259 HRESULT hrSI, hrSH, hrSF;
2264 SHGetDesktopFolder(&psf);
2265 for(i = 0; flags[i] != -1234; i++)
2267 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2268 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2269 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2270 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2271 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2272 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2274 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2275 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2279 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2281 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2283 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2285 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2286 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2288 IShellFolder_Release(psf);
2290 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2291 ok(hrSI == E_INVALIDARG, "Got 0x%08x\n", hrSI);
2292 res = SHGetPathFromIDListW(pidl, buf);
2293 ok(res == FALSE, "Got %d\n", res);
2294 if(SUCCEEDED(hrSI) && res)
2295 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2296 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2298 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2299 todo_wine ok(hres == E_NOTIMPL /* Win7 */ || hres == S_OK /* Vista */,
2300 "Got 0x%08x\n", hres);
2301 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2303 IShellItem_Release(shellitem);
2308 static void test_SHGetItemFromDataObject(void)
2310 IShellFolder *psfdesktop;
2315 if(!pSHGetItemFromDataObject)
2317 win_skip("No SHGetItemFromDataObject.\n");
2323 /* Crashes under win7 */
2324 hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, NULL);
2327 hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, (void**)&psv);
2328 ok(hres == E_INVALIDARG, "got 0x%08x\n", hres);
2330 SHGetDesktopFolder(&psfdesktop);
2332 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
2333 ok(hres == S_OK, "got 0x%08x\n", hres);
2340 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
2341 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
2342 ok(hres == S_OK, "got 0x%08x\n", hres);
2345 LPITEMIDLIST apidl[5];
2348 for(count = 0; count < 5; count++)
2349 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
2354 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
2355 &IID_IDataObject, NULL, (void**)&pdo);
2356 ok(hres == S_OK, "got 0x%08x\n", hres);
2359 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2360 ok(hres == S_OK, "got 0x%08x\n", hres);
2361 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2362 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2363 ok(hres == S_OK, "got 0x%08x\n", hres);
2364 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2365 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2366 ok(hres == S_OK, "got 0x%08x\n", hres);
2367 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2368 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2369 ok(hres == S_OK, "got 0x%08x\n", hres);
2370 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2371 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2372 ok(hres == S_OK, "got 0x%08x\n", hres);
2373 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2375 IDataObject_Release(pdo);
2379 skip("No file(s) found - skipping single-file test.\n");
2383 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
2384 &IID_IDataObject, NULL, (void**)&pdo);
2385 ok(hres == S_OK, "got 0x%08x\n", hres);
2388 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2389 ok(hres == S_OK, "got 0x%08x\n", hres);
2390 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2391 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2392 ok(hres == S_OK, "got 0x%08x\n", hres);
2393 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2394 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2395 ok(hres == S_OK, "got 0x%08x\n", hres);
2396 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2397 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2398 ok(hres == S_OK, "got 0x%08x\n", hres);
2399 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2400 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2401 ok(hres == E_FAIL, "got 0x%08x\n", hres);
2402 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2403 IDataObject_Release(pdo);
2407 skip("zero or one file found - skipping multi-file test.\n");
2409 for(i = 0; i < count; i++)
2412 IEnumIDList_Release(peidl);
2415 IShellView_Release(psv);
2418 IShellFolder_Release(psfdesktop);
2421 static void test_ShellItemCompare(void)
2423 IShellItem *psi[9]; /* a\a, a\b, a\c, b\a, .. */
2424 IShellItem *psi_a, *psi_b, *psi_c;
2425 IShellFolder *psf_desktop, *psf_current;
2426 LPITEMIDLIST pidl_cwd;
2427 WCHAR curdirW[MAX_PATH];
2430 static const WCHAR filesW[][9] = {
2431 {'a','\\','a',0}, {'a','\\','b',0}, {'a','\\','c',0},
2432 {'b','\\','a',0}, {'b','\\','b',0}, {'b','\\','c',0},
2433 {'c','\\','a',0}, {'c','\\','b',0}, {'c','\\','c',0} };
2437 if(!pSHCreateShellItem)
2439 win_skip("SHCreateShellItem missing.\n");
2443 GetCurrentDirectoryW(MAX_PATH, curdirW);
2444 if(!lstrlenW(curdirW))
2446 skip("Failed to get current directory, skipping.\n");
2450 CreateDirectoryA(".\\a", NULL);
2451 CreateDirectoryA(".\\b", NULL);
2452 CreateDirectoryA(".\\c", NULL);
2453 CreateTestFile(".\\a\\a");
2454 CreateTestFile(".\\a\\b");
2455 CreateTestFile(".\\a\\c");
2456 CreateTestFile(".\\b\\a");
2457 CreateTestFile(".\\b\\b");
2458 CreateTestFile(".\\b\\c");
2459 CreateTestFile(".\\c\\a");
2460 CreateTestFile(".\\c\\b");
2461 CreateTestFile(".\\c\\c");
2463 SHGetDesktopFolder(&psf_desktop);
2464 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2465 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2466 hr = IShellFolder_BindToObject(psf_desktop, pidl_cwd, NULL, &IID_IShellFolder, (void**)&psf_current);
2467 ok(SUCCEEDED(hr), "BindToObject returned %x\n", hr);
2468 IShellFolder_Release(psf_desktop);
2470 /* Generate ShellItems for the files */
2471 ZeroMemory(&psi, sizeof(IShellItem*)*9);
2473 for(i = 0; i < 9; i++)
2475 LPITEMIDLIST pidl_testfile = NULL;
2477 hr = IShellFolder_ParseDisplayName(psf_current, NULL, NULL, (LPWSTR)filesW[i],
2478 NULL, &pidl_testfile, NULL);
2479 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2482 hr = pSHCreateShellItem(NULL, NULL, pidl_testfile, &psi[i]);
2483 ok(hr == S_OK, "Got 0x%08x\n", hr);
2484 pILFree(pidl_testfile);
2486 if(FAILED(hr)) failed = TRUE;
2490 skip("Failed to create all shellitems. \n");
2494 /* Generate ShellItems for the folders */
2495 psi_a = psi_b = psi_c = NULL;
2496 hr = IShellItem_GetParent(psi[0], &psi_a);
2497 ok(hr == S_OK, "Got 0x%08x\n", hr);
2498 if(FAILED(hr)) failed = TRUE;
2499 hr = IShellItem_GetParent(psi[3], &psi_b);
2500 ok(hr == S_OK, "Got 0x%08x\n", hr);
2501 if(FAILED(hr)) failed = TRUE;
2502 hr = IShellItem_GetParent(psi[6], &psi_c);
2503 ok(hr == S_OK, "Got 0x%08x\n", hr);
2504 if(FAILED(hr)) failed = TRUE;
2508 skip("Failed to create shellitems. \n");
2514 /* Crashes on native (win7, winxp) */
2515 hr = IShellItem_Compare(psi_a, NULL, 0, NULL);
2516 hr = IShellItem_Compare(psi_a, psi_b, 0, NULL);
2517 hr = IShellItem_Compare(psi_a, NULL, 0, &order);
2521 for(i = 0; i < 9; i++)
2523 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_DISPLAY, &order);
2524 ok(hr == S_OK, "Got 0x%08x\n", hr);
2525 ok(order == 0, "Got order %d\n", order);
2526 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_CANONICAL, &order);
2527 ok(hr == S_OK, "Got 0x%08x\n", hr);
2528 ok(order == 0, "Got order %d\n", order);
2529 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_ALLFIELDS, &order);
2530 ok(hr == S_OK, "Got 0x%08x\n", hr);
2531 ok(order == 0, "Got order %d\n", order);
2535 /* a\b:a\a , a\b:a\c, a\b:a\b */
2536 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_DISPLAY, &order);
2537 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2538 ok(order == 1, "Got order %d\n", order);
2539 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_DISPLAY, &order);
2540 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2541 ok(order == -1, "Got order %d\n", order);
2542 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_DISPLAY, &order);
2543 ok(hr == S_OK, "Got 0x%08x\n", hr);
2544 ok(order == 0, "Got order %d\n", order);
2546 /* b\b:a\b, b\b:c\b, b\b:c\b */
2547 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_DISPLAY, &order);
2548 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2549 ok(order == 1, "Got order %d\n", order);
2550 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_DISPLAY, &order);
2551 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2552 ok(order == -1, "Got order %d\n", order);
2553 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_DISPLAY, &order);
2554 ok(hr == S_OK, "Got 0x%08x\n", hr);
2555 ok(order == 0, "Got order %d\n", order);
2557 /* b:a\a, b:a\c, b:a\b */
2558 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_DISPLAY, &order);
2559 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2560 todo_wine ok(order == 1, "Got order %d\n", order);
2561 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_DISPLAY, &order);
2562 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2563 todo_wine ok(order == 1, "Got order %d\n", order);
2564 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_DISPLAY, &order);
2565 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2566 todo_wine ok(order == 1, "Got order %d\n", order);
2568 /* b:c\a, b:c\c, b:c\b */
2569 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_DISPLAY, &order);
2570 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2571 ok(order == -1, "Got order %d\n", order);
2572 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_DISPLAY, &order);
2573 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2574 ok(order == -1, "Got order %d\n", order);
2575 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_DISPLAY, &order);
2576 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2577 ok(order == -1, "Got order %d\n", order);
2579 /* a\b:a\a , a\b:a\c, a\b:a\b */
2580 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_CANONICAL, &order);
2581 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2582 ok(order == 1, "Got order %d\n", order);
2583 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_CANONICAL, &order);
2584 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2585 ok(order == -1, "Got order %d\n", order);
2586 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_CANONICAL, &order);
2587 ok(hr == S_OK, "Got 0x%08x\n", hr);
2588 ok(order == 0, "Got order %d\n", order);
2590 /* b\b:a\b, b\b:c\b, b\b:c\b */
2591 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_CANONICAL, &order);
2592 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2593 ok(order == 1, "Got order %d\n", order);
2594 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_CANONICAL, &order);
2595 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2596 ok(order == -1, "Got order %d\n", order);
2597 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_CANONICAL, &order);
2598 ok(hr == S_OK, "Got 0x%08x\n", hr);
2599 ok(order == 0, "Got order %d\n", order);
2601 /* b:a\a, b:a\c, b:a\b */
2602 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_CANONICAL, &order);
2603 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2604 todo_wine ok(order == 1, "Got order %d\n", order);
2605 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_CANONICAL, &order);
2606 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2607 todo_wine ok(order == 1, "Got order %d\n", order);
2608 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_CANONICAL, &order);
2609 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2610 todo_wine ok(order == 1, "Got order %d\n", order);
2612 /* b:c\a, b:c\c, b:c\b */
2613 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_CANONICAL, &order);
2614 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2615 ok(order == -1, "Got order %d\n", order);
2616 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_CANONICAL, &order);
2617 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2618 ok(order == -1, "Got order %d\n", order);
2619 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_CANONICAL, &order);
2620 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2621 ok(order == -1, "Got order %d\n", order);
2624 IShellFolder_Release(psf_current);
2626 DeleteFileA(".\\a\\a");
2627 DeleteFileA(".\\a\\b");
2628 DeleteFileA(".\\a\\c");
2629 DeleteFileA(".\\b\\a");
2630 DeleteFileA(".\\b\\b");
2631 DeleteFileA(".\\b\\c");
2632 DeleteFileA(".\\c\\a");
2633 DeleteFileA(".\\c\\b");
2634 DeleteFileA(".\\c\\c");
2635 RemoveDirectoryA(".\\a");
2636 RemoveDirectoryA(".\\b");
2637 RemoveDirectoryA(".\\c");
2639 if(psi_a) IShellItem_Release(psi_a);
2640 if(psi_b) IShellItem_Release(psi_b);
2641 if(psi_c) IShellItem_Release(psi_c);
2643 for(i = 0; i < 9; i++)
2644 if(psi[i]) IShellItem_Release(psi[i]);
2647 /**************************************************************/
2648 /* IUnknown implementation for counting QueryInterface calls. */
2650 const IUnknownVtbl *lpVtbl;
2658 static HRESULT WINAPI unk_fnQueryInterface(IUnknown *iunk, REFIID riid, void** punk)
2660 IUnknownImpl *This = (IUnknownImpl*)iunk;
2662 for(i = found = 0; This->ifaces[i].id != NULL; i++)
2664 if(IsEqualIID(This->ifaces[i].id, riid))
2666 This->ifaces[i].count++;
2673 return E_NOINTERFACE;
2676 static ULONG WINAPI unk_fnAddRef(IUnknown *iunk)
2681 static ULONG WINAPI unk_fnRelease(IUnknown *iunk)
2686 const IUnknownVtbl vt_IUnknown = {
2687 unk_fnQueryInterface,
2692 static void test_SHGetIDListFromObject(void)
2694 IUnknownImpl *punkimpl;
2695 IShellFolder *psfdesktop;
2697 LPITEMIDLIST pidl, pidl_desktop;
2700 struct if_count ifaces[] =
2701 { {&IID_IPersistIDList, 0},
2702 {&IID_IPersistFolder2, 0},
2703 {&IID_IDataObject, 0},
2704 {&IID_IParentAndItem, 0},
2705 {&IID_IFolderView, 0},
2708 if(!pSHGetIDListFromObject)
2710 win_skip("SHGetIDListFromObject missing.\n");
2714 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
2718 /* Crashes native */
2719 pSHGetIDListFromObject(NULL, NULL);
2720 pSHGetIDListFromObject((void*)0xDEADBEEF, NULL);
2723 hres = pSHGetIDListFromObject(NULL, &pidl);
2724 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
2726 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
2727 punkimpl->lpVtbl = &vt_IUnknown;
2728 punkimpl->ifaces = ifaces;
2729 punkimpl->unknown = 0;
2731 hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
2732 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
2733 ok(ifaces[0].count, "interface not requested.\n");
2734 ok(ifaces[1].count, "interface not requested.\n");
2735 ok(ifaces[2].count, "interface not requested.\n");
2737 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
2738 "interface not requested.\n");
2739 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
2740 "interface not requested.\n");
2742 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
2743 HeapFree(GetProcessHeap(), 0, punkimpl);
2745 pidl_desktop = NULL;
2746 pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
2747 ok(pidl_desktop != NULL, "Failed to get desktop pidl.\n");
2749 SHGetDesktopFolder(&psfdesktop);
2751 /* Test IShellItem */
2752 if(pSHCreateShellItem)
2754 IShellItem *shellitem;
2755 hres = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
2756 ok(hres == S_OK, "got 0x%08x\n", hres);
2759 hres = pSHGetIDListFromObject((IUnknown*)shellitem, &pidl);
2760 ok(hres == S_OK, "got 0x%08x\n", hres);
2763 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
2766 IShellItem_Release(shellitem);
2770 skip("no SHCreateShellItem.\n");
2772 /* Test IShellFolder */
2773 hres = pSHGetIDListFromObject((IUnknown*)psfdesktop, &pidl);
2774 ok(hres == S_OK, "got 0x%08x\n", hres);
2777 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
2781 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
2782 ok(hres == S_OK, "got 0x%08x\n", hres);
2789 /* Test IFolderView */
2790 hres = pSHGetIDListFromObject((IUnknown*)psv, &pidl);
2791 ok(hres == S_OK, "got 0x%08x\n", hres);
2794 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
2798 /* Test IDataObject */
2799 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
2800 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
2801 ok(hres == S_OK, "got 0x%08x\n", hres);
2804 LPITEMIDLIST apidl[5];
2806 for(count = 0; count < 5; count++)
2807 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
2812 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
2813 &IID_IDataObject, NULL, (void**)&pdo);
2814 ok(hres == S_OK, "got 0x%08x\n", hres);
2817 pidl = (void*)0xDEADBEEF;
2818 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
2819 ok(hres == S_OK, "got 0x%08x\n", hres);
2820 ok(pidl != NULL, "pidl is NULL.\n");
2821 ok(ILIsEqual(pidl, apidl[0]), "pidl not equal.\n");
2824 IDataObject_Release(pdo);
2828 skip("No files found - skipping single-file test.\n");
2832 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
2833 &IID_IDataObject, NULL, (void**)&pdo);
2834 ok(hres == S_OK, "got 0x%08x\n", hres);
2837 pidl = (void*)0xDEADBEEF;
2838 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
2839 ok(hres == E_NOINTERFACE || hres == E_FAIL /*Vista*/,
2840 "got 0x%08x\n", hres);
2841 ok(pidl == NULL, "pidl is not NULL.\n");
2843 IDataObject_Release(pdo);
2847 skip("zero or one file found - skipping multi-file test.\n");
2849 for(i = 0; i < count; i++)
2852 IEnumIDList_Release(peidl);
2855 IShellView_Release(psv);
2858 IShellFolder_Release(psfdesktop);
2859 pILFree(pidl_desktop);
2862 static void test_SHGetItemFromObject(void)
2864 IUnknownImpl *punkimpl;
2865 IShellFolder *psfdesktop;
2870 struct if_count ifaces[] =
2871 { {&IID_IPersistIDList, 0},
2872 {&IID_IPersistFolder2, 0},
2873 {&IID_IDataObject, 0},
2874 {&IID_IParentAndItem, 0},
2875 {&IID_IFolderView, 0},
2878 if(!pSHGetItemFromObject)
2880 skip("No SHGetItemFromObject.\n");
2884 SHGetDesktopFolder(&psfdesktop);
2888 /* Crashes with Windows 7 */
2889 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IUnknown, (void**)NULL);
2890 hres = pSHGetItemFromObject(NULL, &IID_IUnknown, (void**)NULL);
2891 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, NULL, (void**)&punk);
2894 hres = pSHGetItemFromObject(NULL, &IID_IUnknown, (void**)&punk);
2895 ok(hres == E_NOINTERFACE, "Got 0x%08x\n", hres);
2897 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
2898 punkimpl->lpVtbl = &vt_IUnknown;
2899 punkimpl->ifaces = ifaces;
2900 punkimpl->unknown = 0;
2902 /* The same as SHGetIDListFromObject */
2903 hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
2904 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
2905 ok(ifaces[0].count, "interface not requested.\n");
2906 ok(ifaces[1].count, "interface not requested.\n");
2907 ok(ifaces[2].count, "interface not requested.\n");
2909 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
2910 "interface not requested.\n");
2911 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
2912 "interface not requested.\n");
2914 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
2915 HeapFree(GetProcessHeap(), 0, punkimpl);
2917 /* Test IShellItem */
2918 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IShellItem, (void**)&psi);
2919 ok(hres == S_OK, "Got 0x%08x\n", hres);
2923 hres = pSHGetItemFromObject((IUnknown*)psi, &IID_IShellItem, (void**)&psi2);
2924 ok(hres == S_OK, "Got 0x%08x\n", hres);
2928 ok(psi == psi2, "Different instances (%p != %p).\n", psi, psi2);
2929 IShellItem_Release(psi2);
2931 IShellItem_Release(psi);
2934 IShellFolder_Release(psfdesktop);
2937 static void test_SHCreateShellItemArray(void)
2939 IShellFolder *pdesktopsf, *psf;
2940 IShellItemArray *psia;
2943 WCHAR cTestDirW[MAX_PATH];
2944 LPITEMIDLIST pidl_testdir, pidl;
2945 static const WCHAR testdirW[] = {'t','e','s','t','d','i','r',0};
2947 if(!pSHCreateShellItemArray) {
2948 skip("No pSHCreateShellItemArray!\n");
2952 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
2956 /* Crashes under native */
2957 pSHCreateShellItemArray(NULL, NULL, 0, NULL, NULL);
2958 pSHCreateShellItemArray(NULL, NULL, 1, NULL, NULL);
2959 pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, NULL);
2960 pSHCreateShellItemArray(pidl, NULL, 0, NULL, NULL);
2963 hr = pSHCreateShellItemArray(NULL, NULL, 0, NULL, &psia);
2964 ok(hr == E_POINTER, "got 0x%08x\n", hr);
2966 SHGetDesktopFolder(&pdesktopsf);
2967 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, &psia);
2968 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2970 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 1, NULL, &psia);
2971 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2973 pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
2974 hr = pSHCreateShellItemArray(pidl, NULL, 0, NULL, &psia);
2975 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2978 GetCurrentDirectoryW(MAX_PATH, cTestDirW);
2979 myPathAddBackslashW(cTestDirW);
2980 lstrcatW(cTestDirW, testdirW);
2982 CreateFilesFolders();
2984 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, cTestDirW, NULL, &pidl_testdir, 0);
2985 ok(hr == S_OK, "got 0x%08x\n", hr);
2988 hr = IShellFolder_BindToObject(pdesktopsf, pidl_testdir, NULL, (REFIID)&IID_IShellFolder,
2990 ok(hr == S_OK, "Got 0x%08x\n", hr);
2992 IShellFolder_Release(pdesktopsf);
2996 skip("Failed to set up environment for SHCreateShellItemArray tests.\n");
2997 pILFree(pidl_testdir);
3002 hr = IShellFolder_EnumObjects(psf, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &peidl);
3003 ok(hr == S_OK, "Got %08x\n", hr);
3006 LPITEMIDLIST apidl[5];
3007 UINT done, numitems, i;
3009 for(done = 0; done < 5; done++)
3010 if(IEnumIDList_Next(peidl, 1, &apidl[done], NULL) != S_OK)
3012 ok(done == 5, "Got %d pidls\n", done);
3013 IEnumIDList_Release(peidl);
3015 /* Create a ShellItemArray */
3016 hr = pSHCreateShellItemArray(NULL, psf, done, (LPCITEMIDLIST*)apidl, &psia);
3017 ok(hr == S_OK, "Got 0x%08x\n", hr);
3024 /* Crashes in Windows 7 */
3025 hr = IShellItemArray_GetCount(psia, NULL);
3028 IShellItemArray_GetCount(psia, &numitems);
3029 ok(numitems == done, "Got %d, expected %d\n", numitems, done);
3031 hr = IShellItemArray_GetItemAt(psia, numitems, &psi);
3032 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3034 /* Compare all the items */
3035 for(i = 0; i < numitems; i++)
3037 LPITEMIDLIST pidl_abs;
3038 pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3040 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3041 ok(hr == S_OK, "(%d) Failed with 0x%08x\n", i, hr);
3044 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3045 ok(hr == S_OK, "Got 0x%08x\n", hr);
3048 ok(ILIsEqual(pidl_abs, pidl), "Pidl not equal.\n");
3051 IShellItem_Release(psi);
3055 for(i = 0; i < done; i++)
3057 IShellItemArray_Release(psia);
3061 /* SHCreateShellItemArrayFromShellItem */
3062 if(pSHCreateShellItemArrayFromShellItem)
3068 /* Crashes under Windows 7 */
3069 hr = pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, NULL);
3070 hr = pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, (void**)&psia);
3071 hr = pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, NULL);
3074 hr = pSHCreateItemFromIDList(pidl_testdir, &IID_IShellItem, (void**)&psi);
3075 ok(hr == S_OK, "Got 0x%08x\n", hr);
3078 hr = pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, (void**)&psia);
3079 ok(hr == S_OK, "Got 0x%08x\n", hr);
3084 hr = IShellItemArray_GetCount(psia, &count);
3085 ok(hr == S_OK, "Got 0x%08x\n", hr);
3086 ok(count == 1, "Got count %d\n", count);
3087 hr = IShellItemArray_GetItemAt(psia, 0, &psi2);
3088 ok(hr == S_OK, "Got 0x%08x\n", hr);
3090 ok(psi != psi2, "ShellItems are of the same instance.\n");
3093 LPITEMIDLIST pidl1, pidl2;
3094 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl1);
3095 ok(hr == S_OK, "Got 0x%08x\n", hr);
3096 ok(pidl1 != NULL, "pidl1 was null.\n");
3097 hr = pSHGetIDListFromObject((IUnknown*)psi2, &pidl2);
3098 ok(hr == S_OK, "Got 0x%08x\n", hr);
3099 ok(pidl2 != NULL, "pidl2 was null.\n");
3100 ok(ILIsEqual(pidl1, pidl2), "pidls not equal.\n");
3103 IShellItem_Release(psi2);
3105 hr = IShellItemArray_GetItemAt(psia, 1, &psi2);
3106 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3107 IShellItemArray_Release(psia);
3109 IShellItem_Release(psi);
3113 skip("No SHCreateShellItemArrayFromShellItem.\n");
3116 IShellFolder_Release(psf);
3117 pILFree(pidl_testdir);
3121 static void test_SHParseDisplayName(void)
3123 LPITEMIDLIST pidl1, pidl2;
3124 IShellFolder *desktop;
3125 WCHAR dirW[MAX_PATH];
3130 if (!pSHParseDisplayName)
3132 win_skip("SHParseDisplayName isn't available\n");
3138 /* crashes on native */
3139 hr = pSHParseDisplayName(NULL, NULL, NULL, 0, NULL);
3141 hr = pSHParseDisplayName(nameW, NULL, NULL, 0, NULL);
3144 pidl1 = (LPITEMIDLIST)0xdeadbeef;
3145 hr = pSHParseDisplayName(NULL, NULL, &pidl1, 0, NULL);
3146 ok(broken(hr == E_OUTOFMEMORY) /* < Vista */ ||
3147 hr == E_INVALIDARG, "failed %08x\n", hr);
3148 ok(pidl1 == 0, "expected null ptr, got %p\n", pidl1);
3152 hr = pSHParseDisplayName(nameW, NULL, &pidl1, 0, NULL);
3153 ok(hr == S_OK, "failed %08x\n", hr);
3154 hr = SHGetDesktopFolder(&desktop);
3155 ok(hr == S_OK, "failed %08x\n", hr);
3156 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, nameW, NULL, &pidl2, NULL);
3157 ok(hr == S_OK, "failed %08x\n", hr);
3158 ret = pILIsEqual(pidl1, pidl2);
3159 ok(ret == TRUE, "expected equal idls\n");
3164 GetWindowsDirectoryW( dirW, MAX_PATH );
3166 hr = pSHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
3167 ok(hr == S_OK, "failed %08x\n", hr);
3168 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, dirW, NULL, &pidl2, NULL);
3169 ok(hr == S_OK, "failed %08x\n", hr);
3171 ret = pILIsEqual(pidl1, pidl2);
3172 ok(ret == TRUE, "expected equal idls\n");
3176 IShellFolder_Release(desktop);
3179 static void test_desktop_IPersist(void)
3181 IShellFolder *desktop;
3183 IPersistFolder2 *ppf2;
3187 hr = SHGetDesktopFolder(&desktop);
3188 ok(hr == S_OK, "failed %08x\n", hr);
3190 hr = IShellFolder_QueryInterface(desktop, &IID_IPersist, (void**)&persist);
3191 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* NT4, W9X */, "failed %08x\n", hr);
3197 /* crashes on native */
3198 hr = IPersist_GetClassID(persist, NULL);
3200 memset(&clsid, 0, sizeof(clsid));
3201 hr = IPersist_GetClassID(persist, &clsid);
3202 ok(hr == S_OK, "failed %08x\n", hr);
3203 ok(IsEqualIID(&CLSID_ShellDesktop, &clsid), "Expected CLSID_ShellDesktop\n");
3204 IPersist_Release(persist);
3207 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder2, (void**)&ppf2);
3208 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* pre-Vista */, "failed %08x\n", hr);
3211 IPersistFolder *ppf;
3213 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder, (void**)&ppf);
3214 ok(hr == S_OK, "IID_IPersistFolder2 without IID_IPersistFolder.\n");
3216 IPersistFolder_Release(ppf);
3219 hr = IPersistFolder2_Initialize(ppf2, NULL);
3220 ok(hr == S_OK, "got %08x\n", hr);
3224 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl);
3225 ok(hr == S_OK, "got %08x\n", hr);
3226 ok(pidl != NULL, "pidl was NULL.\n");
3227 if(SUCCEEDED(hr)) pILFree(pidl);
3229 IPersistFolder2_Release(ppf2);
3232 IShellFolder_Release(desktop);
3235 static void test_GetUIObject(void)
3237 IShellFolder *psf_desktop;
3241 WCHAR path[MAX_PATH];
3242 const WCHAR filename[] =
3243 {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
3245 if(!pSHBindToParent)
3247 win_skip("SHBindToParent missing.\n");
3251 GetCurrentDirectoryW(MAX_PATH, path);
3254 skip("GetCurrentDirectoryW returned an empty string.\n");
3257 lstrcatW(path, filename);
3258 SHGetDesktopFolder(&psf_desktop);
3260 CreateFilesFolders();
3262 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, path, NULL, &pidl, 0);
3263 ok(hr == S_OK, "Got 0x%08x\n", hr);
3267 LPCITEMIDLIST pidl_child;
3268 hr = pSHBindToParent(pidl, &IID_IShellFolder, (void**)&psf, &pidl_child);
3269 ok(hr == S_OK, "Got 0x%08x\n", hr);
3272 hr = IShellFolder_GetUIObjectOf(psf, NULL, 1, (LPCITEMIDLIST*)&pidl_child,
3273 &IID_IContextMenu, NULL, (void**)&pcm);
3274 ok(hr == S_OK, "Got 0x%08x\n", hr);
3277 HMENU hmenu = CreatePopupMenu();
3278 INT max_id, max_id_check;
3280 const int id_upper_limit = 32767;
3281 hr = IContextMenu_QueryContextMenu(pcm, hmenu, 0, 0, id_upper_limit, CMF_NORMAL);
3282 ok(SUCCEEDED(hr), "Got 0x%08x\n", hr);
3283 max_id = HRESULT_CODE(hr) - 1; /* returns max_id + 1 */
3284 ok(max_id <= id_upper_limit, "Got %d\n", max_id);
3285 count = GetMenuItemCount(hmenu);
3286 ok(count, "Got %d\n", count);
3289 for(i = 0; i < count; i++)
3293 ZeroMemory(&mii, sizeof(MENUITEMINFOA));
3294 mii.cbSize = sizeof(MENUITEMINFOA);
3295 mii.fMask = MIIM_ID | MIIM_FTYPE;
3298 res = GetMenuItemInfoA(hmenu, i, TRUE, &mii);
3299 ok(res, "Failed (last error: %d).\n", GetLastError());
3301 ok( (mii.wID <= id_upper_limit) || (mii.fType & MFT_SEPARATOR),
3302 "Got non-separator ID out of range: %d (type: %x) \n", mii.wID, mii.fType);
3303 if(!(mii.fType & MFT_SEPARATOR))
3304 max_id_check = (mii.wID>max_id_check)?mii.wID:max_id_check;
3306 ok((max_id_check == max_id) ||
3307 (max_id_check == max_id-1 /* Win 7 */),
3308 "Not equal (or near equal), got %d and %d\n", max_id_check, max_id);
3310 #define is_win2k() (pSHGetFolderPathA && !pSHGetFolderPathAndSubDirA)
3312 if(count && !is_win2k()) /* Test is interactive on w2k, so skip */
3314 CMINVOKECOMMANDINFO cmi;
3315 ZeroMemory(&cmi, sizeof(CMINVOKECOMMANDINFO));
3316 cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
3318 /* Attempt to execute non-existing command */
3319 cmi.lpVerb = MAKEINTRESOURCEA(9999);
3320 hr = IContextMenu_InvokeCommand(pcm, &cmi);
3321 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3323 cmi.lpVerb = "foobar_wine_test";
3324 hr = IContextMenu_InvokeCommand(pcm, &cmi);
3325 ok( (hr == E_INVALIDARG) || (hr == E_FAIL /* Win7 */) ||
3326 (hr == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION) /* Vista */),
3327 "Got 0x%08x\n", hr);
3332 IContextMenu_Release(pcm);
3334 IShellFolder_Release(psf);
3336 if(pILFree) pILFree(pidl);
3339 IShellFolder_Release(psf_desktop);
3343 #define verify_pidl(i,p) r_verify_pidl(__LINE__, i, p)
3344 static void r_verify_pidl(unsigned l, LPCITEMIDLIST pidl, const WCHAR *path)
3346 LPCITEMIDLIST child;
3347 IShellFolder *parent;
3351 if(!pSHBindToParent){
3352 win_skip("SHBindToParent is not available, not performing full PIDL verification\n");
3354 ok_(__FILE__,l)(pidl != NULL, "Expected PIDL to be non-NULL\n");
3356 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
3362 ok_(__FILE__,l)(0, "didn't get expected path (%s), instead: NULL\n", wine_dbgstr_w(path));
3366 hr = pSHBindToParent(pidl, &IID_IShellFolder, (LPVOID*)&parent, &child);
3367 ok_(__FILE__,l)(hr == S_OK, "SHBindToParent failed: 0x%08x\n", hr);
3371 hr = IShellFolder_GetDisplayNameOf(parent, child, SHGDN_FORPARSING, &filename);
3372 ok_(__FILE__,l)(hr == S_OK, "GetDisplayNameOf failed: 0x%08x\n", hr);
3374 IShellFolder_Release(parent);
3378 ok_(__FILE__,l)(filename.uType == STRRET_WSTR, "Got unexpected string type: %d\n", filename.uType);
3379 ok_(__FILE__,l)(lstrcmpW(path, filename.pOleStr) == 0,
3380 "didn't get expected path (%s), instead: %s\n",
3381 wine_dbgstr_w(path), wine_dbgstr_w(filename.pOleStr));
3383 IShellFolder_Release(parent);
3385 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
3388 static void test_SHSimpleIDListFromPath(void)
3390 const WCHAR adirW[] = {'C',':','\\','s','i','d','l','f','p','d','i','r',0};
3391 const CHAR adirA[] = "C:\\sidlfpdir";
3392 BOOL br, is_unicode = !(GetVersion() & 0x80000000);
3394 LPITEMIDLIST pidl = NULL;
3396 if(!pSHSimpleIDListFromPathAW){
3397 win_skip("SHSimpleIDListFromPathAW not available\n");
3401 br = CreateDirectoryA(adirA, NULL);
3402 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
3405 pidl = pSHSimpleIDListFromPathAW(adirW);
3407 pidl = pSHSimpleIDListFromPathAW(adirA);
3408 verify_pidl(pidl, adirW);
3411 br = RemoveDirectoryA(adirA);
3412 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
3415 pidl = pSHSimpleIDListFromPathAW(adirW);
3417 pidl = pSHSimpleIDListFromPathAW(adirA);
3418 verify_pidl(pidl, adirW);
3422 /* IFileSystemBindData impl */
3423 static HRESULT WINAPI fsbd_QueryInterface(IFileSystemBindData *fsbd,
3424 REFIID riid, void **ppv)
3426 if(IsEqualIID(riid, &IID_IFileSystemBindData) ||
3427 IsEqualIID(riid, &IID_IUnknown)){
3431 return E_NOINTERFACE;
3434 static ULONG WINAPI fsbd_AddRef(IFileSystemBindData *fsbd)
3439 static ULONG WINAPI fsbd_Release(IFileSystemBindData *fsbd)
3444 static HRESULT WINAPI fsbd_SetFindData(IFileSystemBindData *fsbd,
3445 const WIN32_FIND_DATAW *pfd)
3447 ok(0, "SetFindData called\n");
3451 static HRESULT WINAPI fsbd_GetFindData_nul(IFileSystemBindData *fsbd,
3452 WIN32_FIND_DATAW *pfd)
3454 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
3458 static HRESULT WINAPI fsbd_GetFindData_junk(IFileSystemBindData *fsbd,
3459 WIN32_FIND_DATAW *pfd)
3461 memset(pfd, 0xdeadbeef, sizeof(WIN32_FIND_DATAW));
3465 static HRESULT WINAPI fsbd_GetFindData_invalid(IFileSystemBindData *fsbd,
3466 WIN32_FIND_DATAW *pfd)
3468 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
3469 *pfd->cFileName = 'a';
3470 *pfd->cAlternateFileName = 'a';
3474 static HRESULT WINAPI fsbd_GetFindData_valid(IFileSystemBindData *fsbd,
3475 WIN32_FIND_DATAW *pfd)
3477 static const WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
3478 HANDLE handle = FindFirstFileW(adirW, pfd);
3483 static HRESULT WINAPI fsbd_GetFindData_fail(IFileSystemBindData *fsbd,
3484 WIN32_FIND_DATAW *pfd)
3489 static IFileSystemBindDataVtbl fsbdVtbl = {
3490 fsbd_QueryInterface,
3497 static IFileSystemBindData fsbd = { &fsbdVtbl };
3499 static void test_ParseDisplayNamePBC(void)
3501 WCHAR wFileSystemBindData[] =
3502 {'F','i','l','e',' ','S','y','s','t','e','m',' ','B','i','n','d',' ','D','a','t','a',0};
3503 WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
3504 const HRESULT exp_err = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
3511 /* Check if we support WCHAR functions */
3512 SetLastError(0xdeadbeef);
3513 lstrcmpiW(adirW, adirW);
3514 if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED){
3515 win_skip("Most W-calls are not implemented\n");
3519 hres = SHGetDesktopFolder(&psf);
3520 ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
3522 win_skip("Failed to get IShellFolder, can't run tests\n");
3526 /* fails on unknown dir with no IBindCtx */
3527 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, adirW, NULL, &pidl, NULL);
3528 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
3529 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
3531 /* fails on unknown dir with IBindCtx with no IFileSystemBindData */
3532 hres = CreateBindCtx(0, &pbc);
3533 ok(hres == S_OK, "CreateBindCtx failed: 0x%08x\n", hres);
3535 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3536 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
3537 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
3539 /* unknown dir with IBindCtx with IFileSystemBindData */
3540 hres = IBindCtx_RegisterObjectParam(pbc, wFileSystemBindData, (IUnknown*)&fsbd);
3541 ok(hres == S_OK, "RegisterObjectParam failed: 0x%08x\n", hres);
3543 /* return E_FAIL from GetFindData */
3544 pidl = (ITEMIDLIST*)0xdeadbeef;
3545 fsbdVtbl.GetFindData = fsbd_GetFindData_fail;
3546 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3547 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
3548 "ParseDisplayName failed: 0x%08x\n", hres);
3549 if(SUCCEEDED(hres)){
3550 verify_pidl(pidl, adirW);
3554 /* set FIND_DATA struct to NULLs */
3555 pidl = (ITEMIDLIST*)0xdeadbeef;
3556 fsbdVtbl.GetFindData = fsbd_GetFindData_nul;
3557 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3558 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
3559 "ParseDisplayName failed: 0x%08x\n", hres);
3560 if(SUCCEEDED(hres)){
3561 verify_pidl(pidl, adirW);
3565 /* set FIND_DATA struct to junk */
3566 pidl = (ITEMIDLIST*)0xdeadbeef;
3567 fsbdVtbl.GetFindData = fsbd_GetFindData_junk;
3568 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3569 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
3570 "ParseDisplayName failed: 0x%08x\n", hres);
3571 if(SUCCEEDED(hres)){
3572 verify_pidl(pidl, adirW);
3576 /* set FIND_DATA struct to invalid data */
3577 pidl = (ITEMIDLIST*)0xdeadbeef;
3578 fsbdVtbl.GetFindData = fsbd_GetFindData_invalid;
3579 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3580 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
3581 "ParseDisplayName failed: 0x%08x\n", hres);
3582 if(SUCCEEDED(hres)){
3583 verify_pidl(pidl, adirW);
3587 /* set FIND_DATA struct to valid data */
3588 pidl = (ITEMIDLIST*)0xdeadbeef;
3589 fsbdVtbl.GetFindData = fsbd_GetFindData_valid;
3590 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3591 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
3592 "ParseDisplayName failed: 0x%08x\n", hres);
3593 if(SUCCEEDED(hres)){
3594 verify_pidl(pidl, adirW);
3598 IBindCtx_Release(pbc);
3599 IShellFolder_Release(psf);
3602 START_TEST(shlfolder)
3604 init_function_pointers();
3605 /* if OleInitialize doesn't get called, ParseDisplayName returns
3606 CO_E_NOTINITIALIZED for malformed directory names on win2k. */
3607 OleInitialize(NULL);
3609 test_ParseDisplayName();
3610 test_SHParseDisplayName();
3611 test_BindToObject();
3612 test_EnumObjects_and_CompareIDs();
3613 test_GetDisplayName();
3614 test_GetAttributesOf();
3615 test_SHGetPathFromIDList();
3616 test_CallForAttributes();
3617 test_FolderShortcut();
3618 test_ITEMIDLIST_format();
3619 test_SHGetFolderPathAndSubDirA();
3620 test_LocalizedNames();
3621 test_SHCreateShellItem();
3622 test_SHCreateShellItemArray();
3623 test_desktop_IPersist();
3625 test_SHSimpleIDListFromPath();
3626 test_ParseDisplayNamePBC();
3627 test_SHGetNameFromIDList();
3628 test_SHGetItemFromDataObject();
3629 test_SHGetIDListFromObject();
3630 test_SHGetItemFromObject();
3631 test_ShellItemCompare();