2 * Unit test of the IShellFolder functions.
4 * Copyright 2004 Vitaliy Margolen
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
40 #include "wine/test.h"
43 DEFINE_GUID(IID_IParentAndItem, 0xB3A4B685, 0xB685, 0x4805, 0x99,0xD9, 0x5D,0xEA,0xD2,0x87,0x32,0x36);
47 static HRESULT (WINAPI *pSHBindToParent)(LPCITEMIDLIST, REFIID, LPVOID*, LPCITEMIDLIST*);
48 static HRESULT (WINAPI *pSHGetFolderPathA)(HWND, int, HANDLE, DWORD, LPSTR);
49 static HRESULT (WINAPI *pSHGetFolderPathAndSubDirA)(HWND, int, HANDLE, DWORD, LPCSTR, LPSTR);
50 static BOOL (WINAPI *pSHGetPathFromIDListW)(LPCITEMIDLIST,LPWSTR);
51 static HRESULT (WINAPI *pSHGetSpecialFolderLocation)(HWND, int, LPITEMIDLIST *);
52 static BOOL (WINAPI *pSHGetSpecialFolderPathA)(HWND, LPSTR, int, BOOL);
53 static BOOL (WINAPI *pSHGetSpecialFolderPathW)(HWND, LPWSTR, int, BOOL);
54 static HRESULT (WINAPI *pStrRetToBufW)(STRRET*,LPCITEMIDLIST,LPWSTR,UINT);
55 static LPITEMIDLIST (WINAPI *pILFindLastID)(LPCITEMIDLIST);
56 static void (WINAPI *pILFree)(LPITEMIDLIST);
57 static BOOL (WINAPI *pILIsEqual)(LPCITEMIDLIST, LPCITEMIDLIST);
58 static HRESULT (WINAPI *pSHCreateItemFromIDList)(PCIDLIST_ABSOLUTE pidl, REFIID riid, void **ppv);
59 static HRESULT (WINAPI *pSHCreateItemFromParsingName)(PCWSTR,IBindCtx*,REFIID,void**);
60 static HRESULT (WINAPI *pSHCreateShellItem)(LPCITEMIDLIST,IShellFolder*,LPCITEMIDLIST,IShellItem**);
61 static HRESULT (WINAPI *pSHCreateShellItemArray)(LPCITEMIDLIST,IShellFolder*,UINT,LPCITEMIDLIST*,IShellItemArray**);
62 static HRESULT (WINAPI *pSHCreateShellItemArrayFromDataObject)(IDataObject*, REFIID, void **);
63 static HRESULT (WINAPI *pSHCreateShellItemArrayFromShellItem)(IShellItem*, REFIID, void **);
64 static LPITEMIDLIST (WINAPI *pILCombine)(LPCITEMIDLIST,LPCITEMIDLIST);
65 static HRESULT (WINAPI *pSHParseDisplayName)(LPCWSTR,IBindCtx*,LPITEMIDLIST*,SFGAOF,SFGAOF*);
66 static LPITEMIDLIST (WINAPI *pSHSimpleIDListFromPathAW)(LPCVOID);
67 static HRESULT (WINAPI *pSHGetNameFromIDList)(PCIDLIST_ABSOLUTE,SIGDN,PWSTR*);
68 static HRESULT (WINAPI *pSHGetItemFromDataObject)(IDataObject*,DATAOBJ_GET_ITEM_FLAGS,REFIID,void**);
69 static HRESULT (WINAPI *pSHGetIDListFromObject)(IUnknown*, PIDLIST_ABSOLUTE*);
70 static HRESULT (WINAPI *pSHGetItemFromObject)(IUnknown*,REFIID,void**);
71 static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
73 static int strcmp_wa(LPCWSTR strw, const char *stra)
76 WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL);
77 return lstrcmpA(stra, buf);
80 static void init_function_pointers(void)
86 hmod = GetModuleHandleA("shell32.dll");
88 #define MAKEFUNC(f) (p##f = (void*)GetProcAddress(hmod, #f))
89 MAKEFUNC(SHBindToParent);
90 MAKEFUNC(SHCreateItemFromIDList);
91 MAKEFUNC(SHCreateItemFromParsingName);
92 MAKEFUNC(SHCreateShellItem);
93 MAKEFUNC(SHCreateShellItemArray);
94 MAKEFUNC(SHCreateShellItemArrayFromDataObject);
95 MAKEFUNC(SHCreateShellItemArrayFromShellItem);
96 MAKEFUNC(SHGetFolderPathA);
97 MAKEFUNC(SHGetFolderPathAndSubDirA);
98 MAKEFUNC(SHGetPathFromIDListW);
99 MAKEFUNC(SHGetSpecialFolderPathA);
100 MAKEFUNC(SHGetSpecialFolderPathW);
101 MAKEFUNC(SHGetSpecialFolderLocation);
102 MAKEFUNC(SHParseDisplayName);
103 MAKEFUNC(SHGetNameFromIDList);
104 MAKEFUNC(SHGetItemFromDataObject);
105 MAKEFUNC(SHGetIDListFromObject);
106 MAKEFUNC(SHGetItemFromObject);
109 #define MAKEFUNC_ORD(f, ord) (p##f = (void*)GetProcAddress(hmod, (LPSTR)(ord)))
110 MAKEFUNC_ORD(ILFindLastID, 16);
111 MAKEFUNC_ORD(ILIsEqual, 21);
112 MAKEFUNC_ORD(ILCombine, 25);
113 MAKEFUNC_ORD(ILFree, 155);
114 MAKEFUNC_ORD(SHSimpleIDListFromPathAW, 162);
117 /* test named exports */
118 ptr = GetProcAddress(hmod, "ILFree");
119 ok(broken(ptr == 0) || ptr != 0, "expected named export for ILFree\n");
122 #define TESTNAMED(f) \
123 ptr = (void*)GetProcAddress(hmod, #f); \
124 ok(ptr != 0, "expected named export for " #f "\n");
126 TESTNAMED(ILAppendID);
128 TESTNAMED(ILCloneFirst);
129 TESTNAMED(ILCombine);
130 TESTNAMED(ILCreateFromPath);
131 TESTNAMED(ILCreateFromPathA);
132 TESTNAMED(ILCreateFromPathW);
133 TESTNAMED(ILFindChild);
134 TESTNAMED(ILFindLastID);
135 TESTNAMED(ILGetNext);
136 TESTNAMED(ILGetSize);
137 TESTNAMED(ILIsEqual);
138 TESTNAMED(ILIsParent);
139 TESTNAMED(ILRemoveLastID);
140 TESTNAMED(ILSaveToStream);
144 hmod = GetModuleHandleA("shlwapi.dll");
145 pStrRetToBufW = (void*)GetProcAddress(hmod, "StrRetToBufW");
147 pIsWow64Process = (void*)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process");
149 hr = SHGetMalloc(&ppM);
150 ok(hr == S_OK, "SHGetMalloc failed %08x\n", hr);
153 static void test_ParseDisplayName(void)
156 IShellFolder *IDesktopFolder;
157 static const char *cNonExistDir1A = "c:\\nonexist_subdir";
158 static const char *cNonExistDir2A = "c:\\\\nonexist_subdir";
159 static const char *cInetTestA = "http:\\yyy";
160 static const char *cInetTest2A = "xx:yyy";
162 WCHAR cTestDirW [MAX_PATH] = {0};
166 hr = SHGetDesktopFolder(&IDesktopFolder);
167 ok(hr == S_OK, "Expected SHGetDesktopFolder to return S_OK, got 0x%08x\n", hr);
168 if(hr != S_OK) return;
170 /* Tests crash on W2K and below (SHCreateShellItem available as of XP) */
171 if (pSHCreateShellItem)
173 /* null name and pidl */
174 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
175 NULL, NULL, NULL, NULL, NULL, 0);
176 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
179 newPIDL = (ITEMIDLIST*)0xdeadbeef;
180 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
181 NULL, NULL, NULL, NULL, &newPIDL, 0);
182 ok(newPIDL == 0, "expected null, got %p\n", newPIDL);
183 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
186 win_skip("Tests would crash on W2K and below\n");
188 MultiByteToWideChar(CP_ACP, 0, cInetTestA, -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 MultiByteToWideChar(CP_ACP, 0, cInetTest2A, -1, cTestDirW, MAX_PATH);
201 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
202 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
203 todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
204 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
207 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
208 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
209 IMalloc_Free(ppM, newPIDL);
212 res = GetFileAttributesA(cNonExistDir1A);
213 if(res != INVALID_FILE_ATTRIBUTES)
215 skip("Test directory unexpectedly exists\n");
219 MultiByteToWideChar(CP_ACP, 0, cNonExistDir1A, -1, cTestDirW, MAX_PATH);
220 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
221 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
222 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL),
223 "ParseDisplayName returned %08x, expected 80070002 or E_FAIL\n", hr);
225 res = GetFileAttributesA(cNonExistDir2A);
226 if(res != INVALID_FILE_ATTRIBUTES)
228 skip("Test directory unexpectedly exists\n");
232 MultiByteToWideChar(CP_ACP, 0, cNonExistDir2A, -1, cTestDirW, MAX_PATH);
233 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
234 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
235 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL) || (hr == E_INVALIDARG),
236 "ParseDisplayName returned %08x, expected 80070002, E_FAIL or E_INVALIDARG\n", hr);
238 /* I thought that perhaps the DesktopFolder's ParseDisplayName would recognize the
239 * path corresponding to CSIDL_PERSONAL and return a CLSID_MyDocuments PIDL. Turns
240 * out it doesn't. The magic seems to happen in the file dialogs, then. */
241 if (!pSHGetSpecialFolderPathW || !pILFindLastID)
243 win_skip("SHGetSpecialFolderPathW and/or ILFindLastID are not available\n");
247 bRes = pSHGetSpecialFolderPathW(NULL, cTestDirW, CSIDL_PERSONAL, FALSE);
248 ok(bRes, "SHGetSpecialFolderPath(CSIDL_PERSONAL) failed! %u\n", GetLastError());
249 if (!bRes) goto finished;
251 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
252 ok(hr == S_OK, "DesktopFolder->ParseDisplayName failed. hr = %08x.\n", hr);
253 if (hr != S_OK) goto finished;
255 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x31 ||
256 pILFindLastID(newPIDL)->mkid.abID[0] == 0xb1, /* Win98 */
257 "Last pidl should be of type PT_FOLDER or PT_IESPECIAL2, but is: %02x\n",
258 pILFindLastID(newPIDL)->mkid.abID[0]);
259 IMalloc_Free(ppM, newPIDL);
262 IShellFolder_Release(IDesktopFolder);
265 /* creates a file with the specified name for tests */
266 static void CreateTestFile(const CHAR *name)
271 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
272 if (file != INVALID_HANDLE_VALUE)
274 WriteFile(file, name, strlen(name), &written, NULL);
275 WriteFile(file, "\n", strlen("\n"), &written, NULL);
281 /* initializes the tests */
282 static void CreateFilesFolders(void)
284 CreateDirectoryA(".\\testdir", NULL);
285 CreateDirectoryA(".\\testdir\\test.txt", NULL);
286 CreateTestFile (".\\testdir\\test1.txt ");
287 CreateTestFile (".\\testdir\\test2.txt ");
288 CreateTestFile (".\\testdir\\test3.txt ");
289 CreateDirectoryA(".\\testdir\\testdir2 ", NULL);
290 CreateDirectoryA(".\\testdir\\testdir2\\subdir", NULL);
293 /* cleans after tests */
294 static void Cleanup(void)
296 DeleteFileA(".\\testdir\\test1.txt");
297 DeleteFileA(".\\testdir\\test2.txt");
298 DeleteFileA(".\\testdir\\test3.txt");
299 RemoveDirectoryA(".\\testdir\\test.txt");
300 RemoveDirectoryA(".\\testdir\\testdir2\\subdir");
301 RemoveDirectoryA(".\\testdir\\testdir2");
302 RemoveDirectoryA(".\\testdir");
307 static void test_EnumObjects(IShellFolder *iFolder)
309 IEnumIDList *iEnumList;
310 LPITEMIDLIST newPIDL, idlArr[10];
315 static const WORD iResults [5][5] =
324 #define SFGAO_testfor SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | SFGAO_CAPABILITYMASK
325 /* Don't test for SFGAO_HASSUBFOLDER since we return real state and native cached */
326 static const ULONG attrs[5] =
328 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
329 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
330 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
331 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
332 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
335 hr = IShellFolder_EnumObjects(iFolder, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &iEnumList);
336 ok(hr == S_OK, "EnumObjects failed %08x\n", hr);
338 /* This is to show that, contrary to what is said on MSDN, on IEnumIDList::Next,
339 * the filesystem shellfolders return S_OK even if less than 'celt' items are
340 * returned (in contrast to S_FALSE). We have to do it in a loop since WinXP
341 * only ever returns a single entry per call. */
342 while (IEnumIDList_Next(iEnumList, 10-i, &idlArr[i], &NumPIDLs) == S_OK)
344 ok (i == 5, "i: %d\n", i);
346 hr = IEnumIDList_Release(iEnumList);
347 ok(hr == S_OK, "IEnumIDList_Release failed %08x\n", hr);
349 /* Sort them first in case of wrong order from system */
350 for (i=0;i<5;i++) for (j=0;j<5;j++)
351 if ((SHORT)IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]) < 0)
354 idlArr[i] = idlArr[j];
358 for (i=0;i<5;i++) for (j=0;j<5;j++)
360 hr = IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]);
361 ok(hr == iResults[i][j], "Got %x expected [%d]-[%d]=%x\n", hr, i, j, iResults[i][j]);
365 for (i = 0; i < 5; i++)
368 #define SFGAO_VISTA SFGAO_DROPTARGET | SFGAO_CANLINK | SFGAO_CANCOPY
369 /* Native returns all flags no matter what we ask for */
370 flags = SFGAO_CANCOPY;
371 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
372 flags &= SFGAO_testfor;
373 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
374 ok(flags == (attrs[i]) ||
375 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR) || /* Win9x, NT4 */
376 flags == ((attrs[i] & ~SFGAO_CAPABILITYMASK) | SFGAO_VISTA), /* Vista and higher */
377 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
379 flags = SFGAO_testfor;
380 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
381 flags &= SFGAO_testfor;
382 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
383 ok(flags == attrs[i] ||
384 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR), /* Win9x, NT4 */
385 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
389 IMalloc_Free(ppM, idlArr[i]);
392 static void test_BindToObject(void)
396 IShellFolder *psfDesktop, *psfChild, *psfMyComputer, *psfSystemDir;
397 SHITEMID emptyitem = { 0, { 0 } };
398 LPITEMIDLIST pidlMyComputer, pidlSystemDir, pidlEmpty = (LPITEMIDLIST)&emptyitem;
399 WCHAR wszSystemDir[MAX_PATH];
400 char szSystemDir[MAX_PATH];
401 WCHAR wszMyComputer[] = {
402 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
403 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
405 /* The following tests shows that BindToObject should fail with E_INVALIDARG if called
406 * with an empty pidl. This is tested for Desktop, MyComputer and the FS ShellFolder
408 hr = SHGetDesktopFolder(&psfDesktop);
409 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
410 if (hr != S_OK) return;
412 hr = IShellFolder_BindToObject(psfDesktop, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
413 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
415 hr = IShellFolder_BindToObject(psfDesktop, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
416 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
418 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
419 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
421 IShellFolder_Release(psfDesktop);
425 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
426 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
427 IShellFolder_Release(psfDesktop);
428 IMalloc_Free(ppM, pidlMyComputer);
429 if (hr != S_OK) return;
431 hr = IShellFolder_BindToObject(psfMyComputer, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
432 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
436 /* this call segfaults on 98SE */
437 hr = IShellFolder_BindToObject(psfMyComputer, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
438 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
441 cChars = GetSystemDirectoryA(szSystemDir, MAX_PATH);
442 ok (cChars > 0 && cChars < MAX_PATH, "GetSystemDirectoryA failed! LastError: %u\n", GetLastError());
443 if (cChars == 0 || cChars >= MAX_PATH) {
444 IShellFolder_Release(psfMyComputer);
447 MultiByteToWideChar(CP_ACP, 0, szSystemDir, -1, wszSystemDir, MAX_PATH);
449 hr = IShellFolder_ParseDisplayName(psfMyComputer, NULL, NULL, wszSystemDir, NULL, &pidlSystemDir, NULL);
450 ok (hr == S_OK, "MyComputers's ParseDisplayName failed to parse the SystemDirectory! hr = %08x\n", hr);
452 IShellFolder_Release(psfMyComputer);
456 hr = IShellFolder_BindToObject(psfMyComputer, pidlSystemDir, NULL, &IID_IShellFolder, (LPVOID*)&psfSystemDir);
457 ok (hr == S_OK, "MyComputer failed to bind to a FileSystem ShellFolder! hr = %08x\n", hr);
458 IShellFolder_Release(psfMyComputer);
459 IMalloc_Free(ppM, pidlSystemDir);
460 if (hr != S_OK) return;
462 hr = IShellFolder_BindToObject(psfSystemDir, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
463 ok (hr == E_INVALIDARG,
464 "FileSystem ShellFolder's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
468 /* this call segfaults on 98SE */
469 hr = IShellFolder_BindToObject(psfSystemDir, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
470 ok (hr == E_INVALIDARG,
471 "FileSystem ShellFolder's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
474 IShellFolder_Release(psfSystemDir);
477 /* Based on PathAddBackslashW from dlls/shlwapi/path.c */
478 static LPWSTR myPathAddBackslashW( LPWSTR lpszPath )
482 if (!lpszPath || (iLen = lstrlenW(lpszPath)) >= MAX_PATH)
488 if (lpszPath[-1] != '\\')
497 static void test_GetDisplayName(void)
502 WCHAR wszTestFile[MAX_PATH], wszTestFile2[MAX_PATH];
503 char szTestFile[MAX_PATH], szTestDir[MAX_PATH];
506 LPSHELLFOLDER psfDesktop, psfPersonal;
508 SHITEMID emptyitem = { 0, { 0 } };
509 LPITEMIDLIST pidlTestFile, pidlEmpty = (LPITEMIDLIST)&emptyitem;
510 LPCITEMIDLIST pidlLast;
511 static const CHAR szFileName[] = "winetest.foo";
512 static const WCHAR wszFileName[] = { 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
513 static const WCHAR wszDirName[] = { 'w','i','n','e','t','e','s','t',0 };
515 /* I'm trying to figure if there is a functional difference between calling
516 * SHGetPathFromIDListW and calling GetDisplayNameOf(SHGDN_FORPARSING) after
517 * binding to the shellfolder. One thing I thought of was that perhaps
518 * SHGetPathFromIDListW would be able to get the path to a file, which does
519 * not exist anymore, while the other method wouldn't. It turns out there's
520 * no functional difference in this respect.
523 if(!pSHGetSpecialFolderPathA) {
524 win_skip("SHGetSpecialFolderPathA is not available\n");
528 /* First creating a directory in MyDocuments and a file in this directory. */
529 result = pSHGetSpecialFolderPathA(NULL, szTestDir, CSIDL_PERSONAL, FALSE);
530 ok(result, "SHGetSpecialFolderPathA failed! Last error: %u\n", GetLastError());
533 /* Use ANSI file functions so this works on Windows 9x */
534 lstrcatA(szTestDir, "\\winetest");
535 CreateDirectoryA(szTestDir, NULL);
536 attr=GetFileAttributesA(szTestDir);
537 if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY))
539 ok(0, "unable to create the '%s' directory\n", szTestDir);
543 lstrcpyA(szTestFile, szTestDir);
544 lstrcatA(szTestFile, "\\");
545 lstrcatA(szTestFile, szFileName);
546 hTestFile = CreateFileA(szTestFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
547 ok((hTestFile != INVALID_HANDLE_VALUE), "CreateFileA failed! Last error: %u\n", GetLastError());
548 if (hTestFile == INVALID_HANDLE_VALUE) return;
549 CloseHandle(hTestFile);
551 /* Getting an itemidlist for the file. */
552 hr = SHGetDesktopFolder(&psfDesktop);
553 ok(hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
554 if (hr != S_OK) return;
556 MultiByteToWideChar(CP_ACP, 0, szTestFile, -1, wszTestFile, MAX_PATH);
558 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
559 ok(hr == S_OK, "Desktop->ParseDisplayName failed! hr = %08x\n", hr);
561 IShellFolder_Release(psfDesktop);
565 pidlLast = pILFindLastID(pidlTestFile);
566 ok(pidlLast->mkid.cb >=76 ||
567 broken(pidlLast->mkid.cb == 28) || /* W2K */
568 broken(pidlLast->mkid.cb == 40), /* Win9x, WinME */
569 "Expected pidl length of at least 76, got %d.\n", pidlLast->mkid.cb);
570 if (pidlLast->mkid.cb >= 28) {
571 ok(!lstrcmpA((CHAR*)&pidlLast->mkid.abID[12], szFileName),
572 "Filename should be stored as ansi-string at this position!\n");
574 /* WinXP and up store the filenames as both ANSI and UNICODE in the pidls */
575 if (pidlLast->mkid.cb >= 76) {
576 ok(!lstrcmpW((WCHAR*)&pidlLast->mkid.abID[46], wszFileName) ||
577 (pidlLast->mkid.cb >= 94 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[64], wszFileName)) || /* Vista */
578 (pidlLast->mkid.cb >= 98 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[68], wszFileName)), /* Win7 */
579 "Filename should be stored as wchar-string at this position!\n");
582 /* It seems as if we cannot bind to regular files on windows, but only directories.
584 hr = IShellFolder_BindToObject(psfDesktop, pidlTestFile, NULL, &IID_IUnknown, (VOID**)&psfFile);
586 ok (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
587 hr == E_NOTIMPL || /* Vista */
588 broken(hr == S_OK), /* Win9x, W2K */
591 IShellFolder_Release(psfFile);
594 if (!pSHBindToParent)
596 win_skip("SHBindToParent is missing\n");
597 DeleteFileA(szTestFile);
598 RemoveDirectoryA(szTestDir);
602 /* Some tests for IShellFolder::SetNameOf */
603 if (pSHGetFolderPathAndSubDirA)
605 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
606 ok(hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
608 /* It's ok to use this fixed path. Call will fail anyway. */
609 WCHAR wszAbsoluteFilename[] = { 'C',':','\\','w','i','n','e','t','e','s','t', 0 };
610 LPITEMIDLIST pidlNew;
612 /* The pidl returned through the last parameter of SetNameOf is a simple one. */
613 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlLast, wszDirName, SHGDN_NORMAL, &pidlNew);
614 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
617 ok (((LPITEMIDLIST)((LPBYTE)pidlNew+pidlNew->mkid.cb))->mkid.cb == 0,
618 "pidl returned from SetNameOf should be simple!\n");
620 /* Passing an absolute path to SetNameOf fails. The HRESULT code indicates that SetNameOf
621 * is implemented on top of SHFileOperation in WinXP. */
622 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszAbsoluteFilename,
623 SHGDN_FORPARSING, NULL);
624 ok (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED), "SetNameOf succeeded! hr = %08x\n", hr);
626 /* Rename the file back to its original name. SetNameOf ignores the fact, that the
627 * SHGDN flags specify an absolute path. */
628 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszFileName, SHGDN_FORPARSING, NULL);
629 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
634 IShellFolder_Release(psfPersonal);
638 win_skip("Avoid needs of interaction on Win2k\n");
640 /* Deleting the file and the directory */
641 DeleteFileA(szTestFile);
642 RemoveDirectoryA(szTestDir);
644 /* SHGetPathFromIDListW still works, although the file is not present anymore. */
645 if (pSHGetPathFromIDListW)
647 result = pSHGetPathFromIDListW(pidlTestFile, wszTestFile2);
648 ok (result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
649 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "SHGetPathFromIDListW returns incorrect path!\n");
652 /* SHBindToParent fails, if called with a NULL PIDL. */
653 hr = pSHBindToParent(NULL, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
654 ok (hr != S_OK, "SHBindToParent(NULL) should fail!\n");
656 /* But it succeeds with an empty PIDL. */
657 hr = pSHBindToParent(pidlEmpty, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
658 ok (hr == S_OK, "SHBindToParent(empty PIDL) should succeed! hr = %08x\n", hr);
659 ok (pidlLast == pidlEmpty, "The last element of an empty PIDL should be the PIDL itself!\n");
661 IShellFolder_Release(psfPersonal);
663 /* Binding to the folder and querying the display name of the file also works. */
664 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
665 ok (hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
667 IShellFolder_Release(psfDesktop);
671 /* This test shows that Windows doesn't allocate a new pidlLast, but returns a pointer into
672 * pidlTestFile (In accordance with MSDN). */
673 ok (pILFindLastID(pidlTestFile) == pidlLast,
674 "SHBindToParent doesn't return the last id of the pidl param!\n");
676 hr = IShellFolder_GetDisplayNameOf(psfPersonal, pidlLast, SHGDN_FORPARSING, &strret);
677 ok (hr == S_OK, "Personal->GetDisplayNameOf failed! hr = %08x\n", hr);
679 IShellFolder_Release(psfDesktop);
680 IShellFolder_Release(psfPersonal);
686 hr = pStrRetToBufW(&strret, pidlLast, wszTestFile2, MAX_PATH);
687 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
688 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "GetDisplayNameOf returns incorrect path!\n");
691 ILFree(pidlTestFile);
692 IShellFolder_Release(psfDesktop);
693 IShellFolder_Release(psfPersonal);
696 static void test_CallForAttributes(void)
702 LPSHELLFOLDER psfDesktop;
703 LPITEMIDLIST pidlMyDocuments;
704 DWORD dwAttributes, dwCallForAttributes, dwOrigAttributes, dwOrigCallForAttributes;
705 static const WCHAR wszAttributes[] = { 'A','t','t','r','i','b','u','t','e','s',0 };
706 static const WCHAR wszCallForAttributes[] = {
707 'C','a','l','l','F','o','r','A','t','t','r','i','b','u','t','e','s',0 };
708 static const WCHAR wszMyDocumentsKey[] = {
709 'C','L','S','I','D','\\','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-',
710 '1','1','D','0','-','9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',
711 '\\','S','h','e','l','l','F','o','l','d','e','r',0 };
712 WCHAR wszMyDocuments[] = {
713 ':',':','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-','1','1','D','0','-',
714 '9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',0 };
716 /* For the root of a namespace extension, the attributes are not queried by binding
717 * to the object and calling GetAttributesOf. Instead, the attributes are read from
718 * the registry value HKCR/CLSID/{...}/ShellFolder/Attributes. This is documented on MSDN.
720 * The MyDocuments shellfolder on WinXP has a HKCR/CLSID/{...}/ShellFolder/CallForAttributes
721 * value. It seems that if the folder is queried for one of the flags set in CallForAttributes,
722 * the shell does bind to the folder object and calls GetAttributesOf. This is not documented
723 * on MSDN. This test is meant to document the observed behaviour on WinXP SP2.
725 hr = SHGetDesktopFolder(&psfDesktop);
726 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
727 if (hr != S_OK) return;
729 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyDocuments, NULL,
730 &pidlMyDocuments, NULL);
732 broken(hr == E_INVALIDARG), /* Win95, NT4 */
733 "Desktop's ParseDisplayName failed to parse MyDocuments's CLSID! hr = %08x\n", hr);
735 IShellFolder_Release(psfDesktop);
739 dwAttributes = 0xffffffff;
740 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
741 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
742 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
744 /* We need the following setup (as observed on WinXP SP2), for the tests to make sense. */
745 ok (dwAttributes & SFGAO_FILESYSTEM, "SFGAO_FILESYSTEM attribute is not set for MyDocuments!\n");
746 ok (!(dwAttributes & SFGAO_ISSLOW), "SFGAO_ISSLOW attribute is set for MyDocuments!\n");
747 ok (!(dwAttributes & SFGAO_GHOSTED), "SFGAO_GHOSTED attribute is set for MyDocuments!\n");
749 /* We don't have the MyDocuments shellfolder in wine yet, and thus we don't have the registry
750 * key. So the test will return at this point, if run on wine.
752 lResult = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszMyDocumentsKey, 0, KEY_WRITE|KEY_READ, &hKey);
753 ok (lResult == ERROR_SUCCESS ||
754 lResult == ERROR_ACCESS_DENIED,
755 "RegOpenKeyEx failed! result: %08x\n", lResult);
756 if (lResult != ERROR_SUCCESS) {
757 if (lResult == ERROR_ACCESS_DENIED)
758 skip("Not enough rights to open the registry key\n");
759 IMalloc_Free(ppM, pidlMyDocuments);
760 IShellFolder_Release(psfDesktop);
764 /* Query MyDocuments' Attributes value, to be able to restore it later. */
765 dwSize = sizeof(DWORD);
766 lResult = RegQueryValueExW(hKey, wszAttributes, NULL, NULL, (LPBYTE)&dwOrigAttributes, &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 /* Query MyDocuments' CallForAttributes value, to be able to restore it later. */
776 dwSize = sizeof(DWORD);
777 lResult = RegQueryValueExW(hKey, wszCallForAttributes, NULL, NULL,
778 (LPBYTE)&dwOrigCallForAttributes, &dwSize);
779 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
780 if (lResult != ERROR_SUCCESS) {
782 IMalloc_Free(ppM, pidlMyDocuments);
783 IShellFolder_Release(psfDesktop);
787 /* Define via the Attributes value that MyDocuments attributes are SFGAO_ISSLOW and
788 * SFGAO_GHOSTED and that MyDocuments should be called for the SFGAO_ISSLOW and
789 * SFGAO_FILESYSTEM attributes. */
790 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED;
791 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwAttributes, sizeof(DWORD));
792 dwCallForAttributes = SFGAO_ISSLOW|SFGAO_FILESYSTEM;
793 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
794 (LPBYTE)&dwCallForAttributes, sizeof(DWORD));
796 /* Although it is not set in CallForAttributes, the SFGAO_GHOSTED flag is reset by
797 * GetAttributesOf. It seems that once there is a single attribute queried, for which
798 * CallForAttributes is set, all flags are taken from the GetAttributesOf call and
799 * the flags in Attributes are ignored.
801 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED|SFGAO_FILESYSTEM;
802 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
803 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
804 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
806 ok (dwAttributes == SFGAO_FILESYSTEM,
807 "Desktop->GetAttributes(MyDocuments) returned unexpected attributes: %08x\n",
810 /* Restore MyDocuments' original Attributes and CallForAttributes registry values */
811 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwOrigAttributes, sizeof(DWORD));
812 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
813 (LPBYTE)&dwOrigCallForAttributes, sizeof(DWORD));
815 IMalloc_Free(ppM, pidlMyDocuments);
816 IShellFolder_Release(psfDesktop);
819 static void test_GetAttributesOf(void)
822 LPSHELLFOLDER psfDesktop, psfMyComputer;
823 SHITEMID emptyitem = { 0, { 0 } };
824 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
825 LPITEMIDLIST pidlMyComputer;
827 static const DWORD desktopFlags[] = {
829 SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSANCESTOR |
830 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
832 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_STREAM | SFGAO_FILESYSANCESTOR |
833 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
834 /* WinMe, Win9x, WinNT*/
835 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSANCESTOR |
836 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
838 static const DWORD myComputerFlags[] = {
840 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
841 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
843 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_STREAM |
844 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
845 /* WinMe, Win9x, WinNT */
846 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
847 SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
848 /* Win95, WinNT when queried directly */
849 SFGAO_CANLINK | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
850 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
852 WCHAR wszMyComputer[] = {
853 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
854 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
855 char cCurrDirA [MAX_PATH] = {0};
856 WCHAR cCurrDirW [MAX_PATH];
857 static WCHAR cTestDirW[] = {'t','e','s','t','d','i','r',0};
858 IShellFolder *IDesktopFolder, *testIShellFolder;
861 BOOL foundFlagsMatch;
863 hr = SHGetDesktopFolder(&psfDesktop);
864 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
865 if (hr != S_OK) return;
867 /* The Desktop attributes can be queried with a single empty itemidlist, .. */
868 dwFlags = 0xffffffff;
869 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, &pidlEmpty, &dwFlags);
870 ok (hr == S_OK, "Desktop->GetAttributesOf(empty pidl) 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 /* .. or with no itemidlist at all. */
880 dwFlags = 0xffffffff;
881 hr = IShellFolder_GetAttributesOf(psfDesktop, 0, NULL, &dwFlags);
882 ok (hr == S_OK, "Desktop->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
883 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
884 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
886 if (desktopFlags[i] == dwFlags)
887 foundFlagsMatch = TRUE;
889 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
891 /* Testing the attributes of the MyComputer shellfolder */
892 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
893 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
895 IShellFolder_Release(psfDesktop);
899 /* Windows sets the SFGAO_CANLINK flag, when MyComputer is queried via the Desktop
900 * folder object. It doesn't do this, if MyComputer is queried directly (see below).
902 dwFlags = 0xffffffff;
903 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, (LPCITEMIDLIST*)&pidlMyComputer, &dwFlags);
904 ok (hr == S_OK, "Desktop->GetAttributesOf(MyComputer) failed! hr = %08x\n", hr);
905 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
906 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
908 if ((myComputerFlags[i] | SFGAO_CANLINK) == dwFlags)
909 foundFlagsMatch = TRUE;
912 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
914 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
915 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
916 IShellFolder_Release(psfDesktop);
917 IMalloc_Free(ppM, pidlMyComputer);
918 if (hr != S_OK) return;
920 hr = IShellFolder_GetAttributesOf(psfMyComputer, 1, &pidlEmpty, &dwFlags);
922 ok (hr == E_INVALIDARG ||
923 broken(hr == S_OK), /* W2K and earlier */
924 "MyComputer->GetAttributesOf(emtpy pidl) should fail! hr = %08x\n", hr);
926 dwFlags = 0xffffffff;
927 hr = IShellFolder_GetAttributesOf(psfMyComputer, 0, NULL, &dwFlags);
928 ok (hr == S_OK, "MyComputer->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
929 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
930 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
932 if (myComputerFlags[i] == dwFlags)
933 foundFlagsMatch = TRUE;
936 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
938 IShellFolder_Release(psfMyComputer);
940 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
941 len = lstrlenA(cCurrDirA);
944 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_GetAttributesOf\n");
947 if (len > 3 && cCurrDirA[len-1] == '\\')
948 cCurrDirA[len-1] = 0;
950 /* create test directory */
951 CreateFilesFolders();
953 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
955 hr = SHGetDesktopFolder(&IDesktopFolder);
956 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
958 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
959 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
961 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
962 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
964 IMalloc_Free(ppM, newPIDL);
966 /* get relative PIDL */
967 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
968 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
970 /* test the shell attributes of the test directory using the relative PIDL */
971 dwFlags = SFGAO_FOLDER;
972 hr = IShellFolder_GetAttributesOf(testIShellFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
973 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
974 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for relative PIDL: %08x\n", dwFlags);
977 IMalloc_Free(ppM, newPIDL);
979 /* append testdirectory name to path */
980 if (cCurrDirA[len-1] == '\\')
981 cCurrDirA[len-1] = 0;
982 lstrcatA(cCurrDirA, "\\testdir");
983 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
985 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
986 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
988 /* test the shell attributes of the test directory using the absolute PIDL */
989 dwFlags = SFGAO_FOLDER;
990 hr = IShellFolder_GetAttributesOf(IDesktopFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
991 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
992 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for absolute PIDL: %08x\n", dwFlags);
995 IMalloc_Free(ppM, newPIDL);
997 IShellFolder_Release(testIShellFolder);
1001 IShellFolder_Release(IDesktopFolder);
1004 static void test_SHGetPathFromIDList(void)
1006 SHITEMID emptyitem = { 0, { 0 } };
1007 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
1008 LPITEMIDLIST pidlMyComputer;
1009 WCHAR wszPath[MAX_PATH], wszDesktop[MAX_PATH];
1012 LPSHELLFOLDER psfDesktop;
1013 WCHAR wszMyComputer[] = {
1014 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
1015 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
1016 WCHAR wszFileName[MAX_PATH];
1017 LPITEMIDLIST pidlTestFile;
1020 static WCHAR wszTestFile[] = {
1021 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
1022 LPITEMIDLIST pidlPrograms;
1024 if(!pSHGetPathFromIDListW || !pSHGetSpecialFolderPathW)
1026 win_skip("SHGetPathFromIDListW() or SHGetSpecialFolderPathW() is missing\n");
1030 /* Calling SHGetPathFromIDListW with no pidl should return the empty string */
1033 result = pSHGetPathFromIDListW(NULL, wszPath);
1034 ok(!result, "Expected failure\n");
1035 ok(!wszPath[0], "Expected empty string\n");
1037 /* Calling SHGetPathFromIDListW with an empty pidl should return the desktop folder's path. */
1038 result = pSHGetSpecialFolderPathW(NULL, wszDesktop, CSIDL_DESKTOP, FALSE);
1039 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOP) failed! Last error: %u\n", GetLastError());
1040 if (!result) return;
1042 /* Check if we are on Win9x */
1043 SetLastError(0xdeadbeef);
1044 lstrcmpiW(wszDesktop, wszDesktop);
1045 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1047 win_skip("Most W-calls are not implemented\n");
1051 result = pSHGetPathFromIDListW(pidlEmpty, wszPath);
1052 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1053 if (!result) return;
1054 ok(!lstrcmpiW(wszDesktop, wszPath), "SHGetPathFromIDListW didn't return desktop path for empty pidl!\n");
1056 /* MyComputer does not map to a filesystem path. SHGetPathFromIDListW should fail. */
1057 hr = SHGetDesktopFolder(&psfDesktop);
1058 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1059 if (hr != S_OK) return;
1061 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1062 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1064 IShellFolder_Release(psfDesktop);
1068 SetLastError(0xdeadbeef);
1071 result = pSHGetPathFromIDListW(pidlMyComputer, wszPath);
1072 ok (!result, "SHGetPathFromIDListW succeeded where it shouldn't!\n");
1073 ok (GetLastError()==0xdeadbeef ||
1074 GetLastError()==ERROR_SUCCESS, /* Vista and higher */
1075 "Unexpected last error from SHGetPathFromIDListW: %u\n", GetLastError());
1076 ok (!wszPath[0], "Expected empty path\n");
1078 IShellFolder_Release(psfDesktop);
1082 IMalloc_Free(ppM, pidlMyComputer);
1084 result = pSHGetSpecialFolderPathW(NULL, wszFileName, CSIDL_DESKTOPDIRECTORY, FALSE);
1085 ok(result, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1087 IShellFolder_Release(psfDesktop);
1090 myPathAddBackslashW(wszFileName);
1091 lstrcatW(wszFileName, wszTestFile);
1092 hTestFile = CreateFileW(wszFileName, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
1093 ok(hTestFile != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: %u\n", GetLastError());
1094 if (hTestFile == INVALID_HANDLE_VALUE) {
1095 IShellFolder_Release(psfDesktop);
1098 CloseHandle(hTestFile);
1100 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
1101 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse filename hr = %08x\n", hr);
1103 IShellFolder_Release(psfDesktop);
1104 DeleteFileW(wszFileName);
1105 IMalloc_Free(ppM, pidlTestFile);
1109 /* This test is to show that the Desktop shellfolder prepends the CSIDL_DESKTOPDIRECTORY
1110 * path for files placed on the desktop, if called with SHGDN_FORPARSING. */
1111 hr = IShellFolder_GetDisplayNameOf(psfDesktop, pidlTestFile, SHGDN_FORPARSING, &strret);
1112 ok (hr == S_OK, "Desktop's GetDisplayNamfOf failed! hr = %08x\n", hr);
1113 IShellFolder_Release(psfDesktop);
1114 DeleteFileW(wszFileName);
1116 IMalloc_Free(ppM, pidlTestFile);
1121 pStrRetToBufW(&strret, pidlTestFile, wszPath, MAX_PATH);
1122 ok(0 == lstrcmpW(wszFileName, wszPath),
1123 "Desktop->GetDisplayNameOf(pidlTestFile, SHGDN_FORPARSING) "
1124 "returned incorrect path for file placed on desktop\n");
1127 result = pSHGetPathFromIDListW(pidlTestFile, wszPath);
1128 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1129 IMalloc_Free(ppM, pidlTestFile);
1130 if (!result) return;
1131 ok(0 == lstrcmpW(wszFileName, wszPath), "SHGetPathFromIDListW returned incorrect path for file placed on desktop\n");
1134 /* Test if we can get the path from the start menu "program files" PIDL. */
1135 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidlPrograms);
1136 ok(hr == S_OK, "SHGetFolderLocation failed: 0x%08x\n", hr);
1138 SetLastError(0xdeadbeef);
1139 result = pSHGetPathFromIDListW(pidlPrograms, wszPath);
1140 IMalloc_Free(ppM, pidlPrograms);
1141 ok(result, "SHGetPathFromIDListW failed\n");
1144 static void test_EnumObjects_and_CompareIDs(void)
1146 ITEMIDLIST *newPIDL;
1147 IShellFolder *IDesktopFolder, *testIShellFolder;
1148 char cCurrDirA [MAX_PATH] = {0};
1149 static const CHAR cTestDirA[] = "\\testdir";
1150 WCHAR cTestDirW[MAX_PATH];
1154 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1155 len = lstrlenA(cCurrDirA);
1158 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_EnumObjects_and_CompareIDs\n");
1161 if(cCurrDirA[len-1] == '\\')
1162 cCurrDirA[len-1] = 0;
1164 lstrcatA(cCurrDirA, cTestDirA);
1165 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cTestDirW, MAX_PATH);
1167 hr = SHGetDesktopFolder(&IDesktopFolder);
1168 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1170 CreateFilesFolders();
1172 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1173 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1175 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1176 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1178 test_EnumObjects(testIShellFolder);
1180 IShellFolder_Release(testIShellFolder);
1184 IMalloc_Free(ppM, newPIDL);
1186 IShellFolder_Release(IDesktopFolder);
1189 /* A simple implementation of an IPropertyBag, which returns fixed values for
1190 * 'Target' and 'Attributes' properties.
1192 static HRESULT WINAPI InitPropertyBag_IPropertyBag_QueryInterface(IPropertyBag *iface, REFIID riid,
1196 return E_INVALIDARG;
1198 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPropertyBag, riid)) {
1201 ok (FALSE, "InitPropertyBag asked for unknown interface!\n");
1202 return E_NOINTERFACE;
1205 IPropertyBag_AddRef(iface);
1209 static ULONG WINAPI InitPropertyBag_IPropertyBag_AddRef(IPropertyBag *iface) {
1213 static ULONG WINAPI InitPropertyBag_IPropertyBag_Release(IPropertyBag *iface) {
1217 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Read(IPropertyBag *iface, LPCOLESTR pszPropName,
1218 VARIANT *pVar, IErrorLog *pErrorLog)
1220 static const WCHAR wszTargetSpecialFolder[] = {
1221 'T','a','r','g','e','t','S','p','e','c','i','a','l','F','o','l','d','e','r',0 };
1222 static const WCHAR wszTarget[] = {
1223 'T','a','r','g','e','t',0 };
1224 static const WCHAR wszAttributes[] = {
1225 'A','t','t','r','i','b','u','t','e','s',0 };
1226 static const WCHAR wszResolveLinkFlags[] = {
1227 'R','e','s','o','l','v','e','L','i','n','k','F','l','a','g','s',0 };
1228 static const WCHAR wszTargetKnownFolder[] = {
1229 'T','a','r','g','e','t','K','n','o','w','n','F','o','l','d','e','r',0 };
1230 static const WCHAR wszCLSID[] = {
1231 'C','L','S','I','D',0 };
1233 if (!lstrcmpW(pszPropName, wszTargetSpecialFolder)) {
1234 ok(V_VT(pVar) == VT_I4 ||
1235 broken(V_VT(pVar) == VT_BSTR), /* Win2k */
1236 "Wrong variant type for 'TargetSpecialFolder' property!\n");
1237 return E_INVALIDARG;
1240 if (!lstrcmpW(pszPropName, wszResolveLinkFlags))
1242 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'ResolveLinkFlags' property!\n");
1243 return E_INVALIDARG;
1246 if (!lstrcmpW(pszPropName, wszTarget)) {
1247 WCHAR wszPath[MAX_PATH];
1250 ok(V_VT(pVar) == VT_BSTR ||
1251 broken(V_VT(pVar) == VT_EMPTY), /* Win2k */
1252 "Wrong variant type for 'Target' property!\n");
1253 if (V_VT(pVar) != VT_BSTR) return E_INVALIDARG;
1255 result = pSHGetSpecialFolderPathW(NULL, wszPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1256 ok(result, "SHGetSpecialFolderPathW(DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1257 if (!result) return E_INVALIDARG;
1259 V_BSTR(pVar) = SysAllocString(wszPath);
1263 if (!lstrcmpW(pszPropName, wszAttributes)) {
1264 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'Attributes' property!\n");
1265 if (V_VT(pVar) != VT_UI4) return E_INVALIDARG;
1266 V_UI4(pVar) = SFGAO_FOLDER|SFGAO_HASSUBFOLDER|SFGAO_FILESYSANCESTOR|
1267 SFGAO_CANRENAME|SFGAO_FILESYSTEM;
1271 if (!lstrcmpW(pszPropName, wszTargetKnownFolder)) {
1272 ok(V_VT(pVar) == VT_BSTR, "Wrong variant type for 'TargetKnownFolder' property!\n");
1274 return E_INVALIDARG;
1277 if (!lstrcmpW(pszPropName, wszCLSID)) {
1278 ok(V_VT(pVar) == VT_EMPTY, "Wrong variant type for 'CLSID' property!\n");
1280 return E_INVALIDARG;
1283 ok(FALSE, "PropertyBag was asked for unknown property %s (vt=%d)!\n", wine_dbgstr_w(pszPropName), V_VT(pVar));
1284 return E_INVALIDARG;
1287 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Write(IPropertyBag *iface, LPCOLESTR pszPropName,
1290 ok(FALSE, "Unexpected call to IPropertyBag_Write\n");
1294 static const IPropertyBagVtbl InitPropertyBag_IPropertyBagVtbl = {
1295 InitPropertyBag_IPropertyBag_QueryInterface,
1296 InitPropertyBag_IPropertyBag_AddRef,
1297 InitPropertyBag_IPropertyBag_Release,
1298 InitPropertyBag_IPropertyBag_Read,
1299 InitPropertyBag_IPropertyBag_Write
1302 static struct IPropertyBag InitPropertyBag = {
1303 &InitPropertyBag_IPropertyBagVtbl
1306 static void test_FolderShortcut(void) {
1307 IPersistPropertyBag *pPersistPropertyBag;
1308 IShellFolder *pShellFolder, *pDesktopFolder;
1309 IPersistFolder3 *pPersistFolder3;
1312 WCHAR wszDesktopPath[MAX_PATH], wszBuffer[MAX_PATH];
1315 LPITEMIDLIST pidlCurrentFolder, pidlWineTestFolder, pidlSubFolder;
1317 WCHAR wszWineTestFolder[] = {
1318 ':',':','{','9','B','3','5','2','E','B','F','-','2','7','6','5','-','4','5','C','1','-',
1319 'B','4','C','6','-','8','5','C','C','7','F','7','A','B','C','6','4','}',0 };
1320 WCHAR wszShellExtKey[] = { 'S','o','f','t','w','a','r','e','\\',
1321 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
1322 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1323 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
1324 'N','a','m','e','S','p','a','c','e','\\',
1325 '{','9','b','3','5','2','e','b','f','-','2','7','6','5','-','4','5','c','1','-',
1326 'b','4','c','6','-','8','5','c','c','7','f','7','a','b','c','6','4','}',0 };
1328 WCHAR wszSomeSubFolder[] = { 'S','u','b','F','o','l','d','e','r', 0};
1329 static const GUID CLSID_UnixDosFolder =
1330 {0x9d20aae8, 0x0625, 0x44b0, {0x9c, 0xa7, 0x71, 0x88, 0x9c, 0x22, 0x54, 0xd9}};
1332 if (!pSHGetSpecialFolderPathW || !pStrRetToBufW) {
1333 win_skip("SHGetSpecialFolderPathW and/or StrRetToBufW are not available\n");
1337 if (!pSHGetFolderPathAndSubDirA)
1339 win_skip("FolderShortcut test doesn't work on Win2k\n");
1343 /* These tests basically show, that CLSID_FolderShortcuts are initialized
1344 * via their IPersistPropertyBag interface. And that the target folder
1345 * is taken from the IPropertyBag's 'Target' property.
1347 hr = CoCreateInstance(&CLSID_FolderShortcut, NULL, CLSCTX_INPROC_SERVER,
1348 &IID_IPersistPropertyBag, (LPVOID*)&pPersistPropertyBag);
1349 if (hr == REGDB_E_CLASSNOTREG) {
1350 win_skip("CLSID_FolderShortcut is not implemented\n");
1353 ok (hr == S_OK, "CoCreateInstance failed! hr = 0x%08x\n", hr);
1354 if (hr != S_OK) return;
1356 hr = IPersistPropertyBag_Load(pPersistPropertyBag, &InitPropertyBag, NULL);
1357 ok(hr == S_OK, "IPersistPropertyBag_Load failed! hr = %08x\n", hr);
1359 IPersistPropertyBag_Release(pPersistPropertyBag);
1363 hr = IPersistPropertyBag_QueryInterface(pPersistPropertyBag, &IID_IShellFolder,
1364 (LPVOID*)&pShellFolder);
1365 IPersistPropertyBag_Release(pPersistPropertyBag);
1366 ok(hr == S_OK, "IPersistPropertyBag_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1367 if (hr != S_OK) return;
1369 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1370 ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1372 IShellFolder_Release(pShellFolder);
1376 result = pSHGetSpecialFolderPathW(NULL, wszDesktopPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1377 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1378 if (!result) return;
1380 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1381 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1383 hr = IShellFolder_QueryInterface(pShellFolder, &IID_IPersistFolder3, (LPVOID*)&pPersistFolder3);
1384 IShellFolder_Release(pShellFolder);
1385 ok(hr == S_OK, "IShellFolder_QueryInterface(IID_IPersistFolder3 failed! hr = 0x%08x\n", hr);
1386 if (hr != S_OK) return;
1388 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1389 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1390 ok(IsEqualCLSID(&clsid, &CLSID_FolderShortcut), "Unexpected CLSID!\n");
1392 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1393 todo_wine ok(hr == S_FALSE, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1394 ok(!pidlCurrentFolder, "IPersistFolder3_GetCurFolder should return a NULL pidl!\n");
1396 /* For FolderShortcut objects, the Initialize method initialized the folder's position in the
1397 * shell namespace. The target folder, read from the property bag above, remains untouched.
1398 * The following tests show this: The itemidlist for some imaginary shellfolder object
1399 * is created and the FolderShortcut is initialized with it. GetCurFolder now returns this
1400 * itemidlist, but GetDisplayNameOf still returns the path from above.
1402 hr = SHGetDesktopFolder(&pDesktopFolder);
1403 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1404 if (hr != S_OK) return;
1406 /* Temporarily register WineTestFolder as a shell namespace extension at the Desktop.
1407 * Otherwise ParseDisplayName fails on WinXP with E_INVALIDARG */
1408 RegCreateKeyW(HKEY_CURRENT_USER, wszShellExtKey, &hShellExtKey);
1409 RegCloseKey(hShellExtKey);
1410 hr = IShellFolder_ParseDisplayName(pDesktopFolder, NULL, NULL, wszWineTestFolder, NULL,
1411 &pidlWineTestFolder, NULL);
1412 RegDeleteKeyW(HKEY_CURRENT_USER, wszShellExtKey);
1413 IShellFolder_Release(pDesktopFolder);
1414 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1415 if (hr != S_OK) return;
1417 hr = IPersistFolder3_Initialize(pPersistFolder3, pidlWineTestFolder);
1418 ok (hr == S_OK, "IPersistFolder3::Initialize failed! hr = %08x\n", hr);
1420 IPersistFolder3_Release(pPersistFolder3);
1421 pILFree(pidlWineTestFolder);
1425 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1426 ok(hr == S_OK, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1427 ok(pILIsEqual(pidlCurrentFolder, pidlWineTestFolder),
1428 "IPersistFolder3_GetCurFolder should return pidlWineTestFolder!\n");
1429 pILFree(pidlCurrentFolder);
1430 pILFree(pidlWineTestFolder);
1432 hr = IPersistFolder3_QueryInterface(pPersistFolder3, &IID_IShellFolder, (LPVOID*)&pShellFolder);
1433 IPersistFolder3_Release(pPersistFolder3);
1434 ok(hr == S_OK, "IPersistFolder3_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1435 if (hr != S_OK) return;
1437 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1438 ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1440 IShellFolder_Release(pShellFolder);
1444 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1445 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1447 /* Next few lines are meant to show that children of FolderShortcuts are not FolderShortcuts,
1448 * but ShellFSFolders. */
1449 myPathAddBackslashW(wszDesktopPath);
1450 lstrcatW(wszDesktopPath, wszSomeSubFolder);
1451 if (!CreateDirectoryW(wszDesktopPath, NULL)) {
1452 IShellFolder_Release(pShellFolder);
1456 hr = IShellFolder_ParseDisplayName(pShellFolder, NULL, NULL, wszSomeSubFolder, NULL,
1457 &pidlSubFolder, NULL);
1458 RemoveDirectoryW(wszDesktopPath);
1459 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1461 IShellFolder_Release(pShellFolder);
1465 hr = IShellFolder_BindToObject(pShellFolder, pidlSubFolder, NULL, &IID_IPersistFolder3,
1466 (LPVOID*)&pPersistFolder3);
1467 IShellFolder_Release(pShellFolder);
1468 pILFree(pidlSubFolder);
1469 ok (hr == S_OK, "IShellFolder::BindToObject failed! hr = %08x\n", hr);
1473 /* On windows, we expect CLSID_ShellFSFolder. On wine we relax this constraint
1474 * a little bit and also allow CLSID_UnixDosFolder. */
1475 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1476 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1477 ok(IsEqualCLSID(&clsid, &CLSID_ShellFSFolder) || IsEqualCLSID(&clsid, &CLSID_UnixDosFolder),
1478 "IPersistFolder3::GetClassID returned unexpected CLSID!\n");
1480 IPersistFolder3_Release(pPersistFolder3);
1483 #include "pshpack1.h"
1484 struct FileStructA {
1488 WORD uFileDate; /* In our current implementation this is */
1489 WORD uFileTime; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastWriteTime) */
1494 struct FileStructW {
1495 WORD cbLen; /* Length of this element. */
1496 BYTE abFooBar1[6]; /* Beyond any recognition. */
1497 WORD uDate; /* FileTimeToDosDate(WIN32_FIND_DATA->ftCreationTime)? */
1498 WORD uTime; /* (this is currently speculation) */
1499 WORD uDate2; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastAccessTime)? */
1500 WORD uTime2; /* (this is currently speculation) */
1501 BYTE abFooBar2[4]; /* Beyond any recognition. */
1502 WCHAR wszName[1]; /* The long filename in unicode. */
1503 /* Just for documentation: Right after the unicode string: */
1504 WORD cbOffset; /* FileStructW's offset from the beginning of the SHITMEID.
1505 * SHITEMID->cb == uOffset + cbLen */
1507 #include "poppack.h"
1509 static void test_ITEMIDLIST_format(void) {
1510 WCHAR wszPersonal[MAX_PATH];
1511 LPSHELLFOLDER psfDesktop, psfPersonal;
1512 LPITEMIDLIST pidlPersonal, pidlFile;
1516 WCHAR wszFile[3][17] = { { 'e','v','e','n','_',0 }, { 'o','d','d','_',0 },
1517 { 'l','o','n','g','e','r','_','t','h','a','n','.','8','_','3',0 } };
1520 if (!pSHGetSpecialFolderPathW) return;
1522 bResult = pSHGetSpecialFolderPathW(NULL, wszPersonal, CSIDL_PERSONAL, FALSE);
1523 ok(bResult, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1524 if (!bResult) return;
1526 SetLastError(0xdeadbeef);
1527 bResult = SetCurrentDirectoryW(wszPersonal);
1528 if (!bResult && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
1529 win_skip("Most W-calls are not implemented\n");
1532 ok(bResult, "SetCurrentDirectory failed! Last error: %u\n", GetLastError());
1533 if (!bResult) return;
1535 hr = SHGetDesktopFolder(&psfDesktop);
1536 ok(hr == S_OK, "SHGetDesktopFolder failed! hr: %08x\n", hr);
1537 if (hr != S_OK) return;
1539 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszPersonal, NULL, &pidlPersonal, NULL);
1540 ok(hr == S_OK, "psfDesktop->ParseDisplayName failed! hr = %08x\n", hr);
1542 IShellFolder_Release(psfDesktop);
1546 hr = IShellFolder_BindToObject(psfDesktop, pidlPersonal, NULL, &IID_IShellFolder,
1547 (LPVOID*)&psfPersonal);
1548 IShellFolder_Release(psfDesktop);
1549 pILFree(pidlPersonal);
1550 ok(hr == S_OK, "psfDesktop->BindToObject failed! hr = %08x\n", hr);
1551 if (hr != S_OK) return;
1553 for (i=0; i<3; i++) {
1554 CHAR szFile[MAX_PATH];
1555 struct FileStructA *pFileStructA;
1558 WideCharToMultiByte(CP_ACP, 0, wszFile[i], -1, szFile, MAX_PATH, NULL, NULL);
1560 hFile = CreateFileW(wszFile[i], GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_FLAG_WRITE_THROUGH, NULL);
1561 ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed! (%u)\n", GetLastError());
1562 if (hFile == INVALID_HANDLE_VALUE) {
1563 IShellFolder_Release(psfPersonal);
1568 hr = IShellFolder_ParseDisplayName(psfPersonal, NULL, NULL, wszFile[i], NULL, &pidlFile, NULL);
1569 DeleteFileW(wszFile[i]);
1570 ok(hr == S_OK, "psfPersonal->ParseDisplayName failed! hr: %08x\n", hr);
1572 IShellFolder_Release(psfPersonal);
1576 pFileStructA = (struct FileStructA *)pidlFile->mkid.abID;
1577 ok(pFileStructA->type == 0x32, "PIDLTYPE should be 0x32!\n");
1578 ok(pFileStructA->dummy == 0x00, "Dummy Byte should be 0x00!\n");
1579 ok(pFileStructA->dwFileSize == 0, "Filesize should be zero!\n");
1581 if (i < 2) /* First two file names are already in valid 8.3 format */
1582 ok(!strcmp(szFile, (CHAR*)&pidlFile->mkid.abID[12]), "Wrong file name!\n");
1584 /* WinXP stores a derived 8.3 dos name (LONGER~1.8_3) here. We probably
1585 * can't implement this correctly, since unix filesystems don't support
1586 * this nasty short/long filename stuff. So we'll probably stay with our
1587 * current habbit of storing the long filename here, which seems to work
1590 ok(pidlFile->mkid.abID[18] == '~' ||
1591 broken(pidlFile->mkid.abID[34] == '~'), /* Win2k */
1592 "Should be derived 8.3 name!\n");
1594 if (i == 0) /* First file name has an even number of chars. No need for alignment. */
1595 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] != '\0' ||
1596 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1), /* Win2k */
1597 "Alignment byte, where there shouldn't be!\n");
1599 if (i == 1) /* Second file name has an uneven number of chars => alignment byte */
1600 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] == '\0',
1601 "There should be an alignment byte, but isn't!\n");
1603 /* The offset of the FileStructW member is stored as a WORD at the end of the pidl. */
1604 cbOffset = *(WORD*)(((LPBYTE)pidlFile)+pidlFile->mkid.cb-sizeof(WORD));
1605 ok ((cbOffset >= sizeof(struct FileStructA) &&
1606 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW)) ||
1607 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1) || /* Win2k on short names */
1608 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 12 + 1), /* Win2k on long names */
1609 "Wrong offset value (%d) stored at the end of the PIDL\n", cbOffset);
1611 if (cbOffset >= sizeof(struct FileStructA) &&
1612 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW))
1614 struct FileStructW *pFileStructW = (struct FileStructW *)(((LPBYTE)pidlFile)+cbOffset);
1616 ok(pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen,
1617 "FileStructW's offset and length should add up to the PIDL's length!\n");
1619 if (pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen) {
1620 /* Since we just created the file, time of creation,
1621 * time of last access and time of last write access just be the same.
1622 * These tests seem to fail sometimes (on WinXP), if the test is run again shortly
1623 * after the first run. I do remember something with NTFS keeping the creation time
1624 * if a file is deleted and then created again within a couple of seconds or so.
1625 * Might be the reason. */
1626 ok (pFileStructA->uFileDate == pFileStructW->uDate &&
1627 pFileStructA->uFileTime == pFileStructW->uTime,
1628 "Last write time should match creation time!\n");
1630 /* On FAT filesystems the last access time is midnight
1631 local time, so the values of uDate2 and uTime2 will
1632 depend on the local timezone. If the times are exactly
1633 equal then the dates should be identical for both FAT
1634 and NTFS as no timezone is more than 1 day away from UTC.
1636 if (pFileStructA->uFileTime == pFileStructW->uTime2)
1638 ok (pFileStructA->uFileDate == pFileStructW->uDate2,
1639 "Last write date and time should match last access date and time!\n");
1643 /* Filesystem may be FAT. Check date within 1 day
1644 and seconds are zero. */
1645 trace ("Filesystem may be FAT. Performing less strict atime test.\n");
1646 ok ((pFileStructW->uTime2 & 0x1F) == 0,
1647 "Last access time on FAT filesystems should have zero seconds.\n");
1648 /* TODO: Perform check for date being within one day.*/
1651 ok (!lstrcmpW(wszFile[i], pFileStructW->wszName) ||
1652 !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 22)) || /* Vista */
1653 !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 26)), /* Win7 */
1654 "The filename should be stored in unicode at this position!\n");
1661 IShellFolder_Release(psfPersonal);
1664 static void test_SHGetFolderPathA(void)
1666 static const BOOL is_win64 = sizeof(void *) > sizeof(int);
1668 char path[MAX_PATH];
1669 char path_x86[MAX_PATH];
1670 char path_key[MAX_PATH];
1674 if (!pSHGetFolderPathA)
1676 win_skip("SHGetFolderPathA not present\n");
1679 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
1681 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES, 0, SHGFP_TYPE_CURRENT, path );
1682 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1683 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILESX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
1686 win_skip( "Program Files (x86) not supported\n" );
1689 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1692 ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1693 ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1694 ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1698 ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1700 ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1702 ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1704 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1706 DWORD type, count = sizeof(path_x86);
1707 if (!RegQueryValueExA( key, "ProgramFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1709 ok( is_win64 || is_wow64, "ProgramFilesDir (x86) exists on 32-bit setup\n" );
1710 ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1712 else ok( !is_win64 && !is_wow64, "ProgramFilesDir (x86) should exist on 64-bit setup\n" );
1716 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMON, 0, SHGFP_TYPE_CURRENT, path );
1717 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1718 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMONX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
1721 win_skip( "Common Files (x86) not supported\n" );
1724 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1727 ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1728 ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1729 ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1733 ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1735 ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1737 ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1739 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1741 DWORD type, count = sizeof(path_x86);
1742 if (!RegQueryValueExA( key, "CommonFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1744 ok( is_win64 || is_wow64, "CommonFilesDir (x86) exists on 32-bit setup\n" );
1745 ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1747 else ok( !is_win64 && !is_wow64, "CommonFilesDir (x86) should exist on 64-bit setup\n" );
1751 static void test_SHGetFolderPathAndSubDirA(void)
1757 static char wine[] = "wine";
1758 static char winetemp[] = "wine\\temp";
1759 static char appdata[MAX_PATH];
1760 static char testpath[MAX_PATH];
1761 static char toolongpath[MAX_PATH+1];
1763 if(!pSHGetFolderPathAndSubDirA)
1765 win_skip("SHGetFolderPathAndSubDirA not present!\n");
1769 if(!pSHGetFolderPathA) {
1770 win_skip("SHGetFolderPathA not present!\n");
1773 if(FAILED(pSHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdata)))
1775 win_skip("SHGetFolderPathA failed for CSIDL_LOCAL_APPDATA!\n");
1779 sprintf(testpath, "%s\\%s", appdata, winetemp);
1780 delret = RemoveDirectoryA(testpath);
1781 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) ) {
1782 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1786 sprintf(testpath, "%s\\%s", appdata, wine);
1787 delret = RemoveDirectoryA(testpath);
1788 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) && (ERROR_FILE_NOT_FOUND != GetLastError())) {
1789 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1793 /* test invalid second parameter */
1794 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | 0xff, NULL, SHGFP_TYPE_CURRENT, wine, testpath);
1795 ok(E_INVALIDARG == ret, "expected E_INVALIDARG, got %x\n", ret);
1797 /* test fourth parameter */
1798 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, 2, winetemp, testpath);
1800 case S_OK: /* winvista */
1801 ok(!strncmp(appdata, testpath, strlen(appdata)),
1802 "expected %s to start with %s\n", testpath, appdata);
1803 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1804 "expected %s to end with %s\n", testpath, winetemp);
1806 case E_INVALIDARG: /* winxp, win2k3 */
1809 ok(0, "expected S_OK or E_INVALIDARG, got %x\n", ret);
1812 /* test fifth parameter */
1814 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, NULL, testpath);
1815 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1816 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1819 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "", testpath);
1820 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1821 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1824 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "\\", testpath);
1825 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1826 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1828 for(i=0; i< MAX_PATH; i++)
1829 toolongpath[i] = '0' + i % 10;
1830 toolongpath[MAX_PATH] = '\0';
1831 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, toolongpath, testpath);
1832 ok(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) == ret,
1833 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), ret);
1836 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wine, NULL);
1837 ok((S_OK == ret) || (E_INVALIDARG == ret), "expected S_OK or E_INVALIDARG, got %x\n", ret);
1839 /* test a not existing path */
1841 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
1842 ok(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == ret,
1843 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), ret);
1845 /* create a directory inside a not existing directory */
1847 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_CREATE | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
1848 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1849 ok(!strncmp(appdata, testpath, strlen(appdata)),
1850 "expected %s to start with %s\n", testpath, appdata);
1851 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1852 "expected %s to end with %s\n", testpath, winetemp);
1853 dwret = GetFileAttributes(testpath);
1854 ok(FILE_ATTRIBUTE_DIRECTORY | dwret, "expected %x to contain FILE_ATTRIBUTE_DIRECTORY\n", dwret);
1857 sprintf(testpath, "%s\\%s", appdata, winetemp);
1858 RemoveDirectoryA(testpath);
1859 sprintf(testpath, "%s\\%s", appdata, wine);
1860 RemoveDirectoryA(testpath);
1863 static void test_LocalizedNames(void)
1865 static char cCurrDirA[MAX_PATH];
1866 WCHAR cCurrDirW[MAX_PATH], tempbufW[25];
1867 IShellFolder *IDesktopFolder, *testIShellFolder;
1868 ITEMIDLIST *newPIDL;
1871 static char resourcefile[MAX_PATH];
1876 static const char desktopini_contents1[] =
1877 "[.ShellClassInfo]\r\n"
1878 "LocalizedResourceName=@";
1879 static const char desktopini_contents2[] =
1881 static WCHAR foldernameW[] = {'t','e','s','t','f','o','l','d','e','r',0};
1882 static const WCHAR folderdisplayW[] = {'F','o','l','d','e','r',' ','N','a','m','e',' ','R','e','s','o','u','r','c','e',0};
1884 /* create folder with desktop.ini and localized name in GetModuleFileNameA(NULL) */
1885 CreateDirectoryA(".\\testfolder", NULL);
1887 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")|FILE_ATTRIBUTE_SYSTEM);
1889 GetModuleFileNameA(NULL, resourcefile, MAX_PATH);
1891 file = CreateFileA(".\\testfolder\\desktop.ini", GENERIC_WRITE, 0, NULL,
1892 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1893 ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %i\n", GetLastError());
1894 ok(WriteFile(file, desktopini_contents1, strlen(desktopini_contents1), &res, NULL) &&
1895 WriteFile(file, resourcefile, strlen(resourcefile), &res, NULL) &&
1896 WriteFile(file, desktopini_contents2, strlen(desktopini_contents2), &res, NULL),
1897 "WriteFile failed %i\n", GetLastError());
1900 /* get IShellFolder for parent */
1901 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1902 len = lstrlenA(cCurrDirA);
1905 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_LocalizedNames\n");
1908 if(cCurrDirA[len-1] == '\\')
1909 cCurrDirA[len-1] = 0;
1911 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1913 hr = SHGetDesktopFolder(&IDesktopFolder);
1914 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1916 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1917 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1919 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1920 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1922 IMalloc_Free(ppM, newPIDL);
1924 /* windows reads the display name from the resource */
1925 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, foldernameW, NULL, &newPIDL, 0);
1926 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1928 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER, &strret);
1929 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1931 if (hr == S_OK && pStrRetToBufW)
1933 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1934 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1936 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
1937 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
1938 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1941 /* editing name is also read from the resource */
1942 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FOREDITING, &strret);
1943 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1945 if (hr == S_OK && pStrRetToBufW)
1947 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1948 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1950 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
1951 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
1952 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1955 /* parsing name is unchanged */
1956 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FORPARSING, &strret);
1957 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1959 if (hr == S_OK && pStrRetToBufW)
1961 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1962 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1963 ok (!lstrcmpiW(tempbufW, foldernameW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1966 IShellFolder_Release(IDesktopFolder);
1967 IShellFolder_Release(testIShellFolder);
1969 IMalloc_Free(ppM, newPIDL);
1972 DeleteFileA(".\\testfolder\\desktop.ini");
1973 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")&~FILE_ATTRIBUTE_SYSTEM);
1974 RemoveDirectoryA(".\\testfolder");
1977 static void test_SHCreateShellItem(void)
1979 IShellItem *shellitem, *shellitem2;
1980 IPersistIDList *persistidl;
1981 LPITEMIDLIST pidl_cwd=NULL, pidl_testfile, pidl_abstestfile, pidl_test, pidl_desktop;
1983 char curdirA[MAX_PATH];
1984 WCHAR curdirW[MAX_PATH];
1985 WCHAR fnbufW[MAX_PATH];
1986 IShellFolder *desktopfolder=NULL, *currentfolder=NULL;
1987 static WCHAR testfileW[] = {'t','e','s','t','f','i','l','e',0};
1989 GetCurrentDirectoryA(MAX_PATH, curdirA);
1991 if (!pSHCreateShellItem)
1993 win_skip("SHCreateShellItem isn't available\n");
1997 if (!lstrlenA(curdirA))
1999 win_skip("GetCurrentDirectoryA returned empty string, skipping test_SHCreateShellItem\n");
2003 if(pSHGetSpecialFolderLocation)
2005 ret = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
2006 ok(ret == S_OK, "Got 0x%08x\n", ret);
2010 win_skip("pSHGetSpecialFolderLocation missing.\n");
2011 pidl_desktop = NULL;
2014 MultiByteToWideChar(CP_ACP, 0, curdirA, -1, curdirW, MAX_PATH);
2016 ret = SHGetDesktopFolder(&desktopfolder);
2017 ok(SUCCEEDED(ret), "SHGetShellFolder returned %x\n", ret);
2019 ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2020 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2022 ret = IShellFolder_BindToObject(desktopfolder, pidl_cwd, NULL, &IID_IShellFolder, (void**)¤tfolder);
2023 ok(SUCCEEDED(ret), "BindToObject returned %x\n", ret);
2025 CreateTestFile(".\\testfile");
2027 ret = IShellFolder_ParseDisplayName(currentfolder, NULL, NULL, testfileW, NULL, &pidl_testfile, NULL);
2028 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2030 pidl_abstestfile = pILCombine(pidl_cwd, pidl_testfile);
2032 ret = pSHCreateShellItem(NULL, NULL, NULL, &shellitem);
2033 ok(ret == E_INVALIDARG, "SHCreateShellItem returned %x\n", ret);
2035 if (0) /* crashes on Windows XP */
2037 pSHCreateShellItem(NULL, NULL, pidl_cwd, NULL);
2038 pSHCreateShellItem(pidl_cwd, NULL, NULL, &shellitem);
2039 pSHCreateShellItem(NULL, currentfolder, NULL, &shellitem);
2040 pSHCreateShellItem(pidl_cwd, currentfolder, NULL, &shellitem);
2043 ret = pSHCreateShellItem(NULL, NULL, pidl_cwd, &shellitem);
2044 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2047 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2048 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2051 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2052 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2055 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2058 IPersistIDList_Release(persistidl);
2060 IShellItem_Release(shellitem);
2063 ret = pSHCreateShellItem(pidl_cwd, NULL, pidl_testfile, &shellitem);
2064 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2067 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2068 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2071 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2072 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2075 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2078 IPersistIDList_Release(persistidl);
2081 ret = IShellItem_GetParent(shellitem, &shellitem2);
2082 ok(SUCCEEDED(ret), "GetParent returned %x\n", ret);
2085 ret = IShellItem_QueryInterface(shellitem2, &IID_IPersistIDList, (void**)&persistidl);
2086 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2089 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2090 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2093 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2096 IPersistIDList_Release(persistidl);
2098 IShellItem_Release(shellitem2);
2101 IShellItem_Release(shellitem);
2104 ret = pSHCreateShellItem(NULL, currentfolder, pidl_testfile, &shellitem);
2105 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2108 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2109 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2112 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2113 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2116 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2119 IPersistIDList_Release(persistidl);
2121 IShellItem_Release(shellitem);
2124 /* if a parent pidl and shellfolder are specified, the shellfolder is ignored */
2125 ret = pSHCreateShellItem(pidl_cwd, desktopfolder, pidl_testfile, &shellitem);
2126 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2129 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2130 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2133 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2134 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2137 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2140 IPersistIDList_Release(persistidl);
2142 IShellItem_Release(shellitem);
2145 ret = pSHCreateShellItem(NULL, desktopfolder, pidl_testfile, &shellitem);
2146 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2149 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2150 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2153 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2154 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2157 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2160 IPersistIDList_Release(persistidl);
2163 IShellItem_Release(shellitem);
2166 ret = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
2167 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2170 ret = IShellItem_GetParent(shellitem, &shellitem2);
2171 ok(FAILED(ret), "Got 0x%08x\n", ret);
2172 if(SUCCEEDED(ret)) IShellItem_Release(shellitem2);
2173 IShellItem_Release(shellitem);
2176 /* SHCreateItemFromParsingName */
2177 if(pSHCreateItemFromParsingName)
2181 /* Crashes under windows 7 */
2182 ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, NULL);
2185 shellitem = (void*)0xdeadbeef;
2186 ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, (void**)&shellitem);
2187 ok(ret == E_INVALIDARG, "SHCreateItemFromParsingName returned %x\n", ret);
2188 ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2190 ret = pSHCreateItemFromParsingName(testfileW, NULL, &IID_IShellItem, (void**)&shellitem);
2191 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
2192 "SHCreateItemFromParsingName returned %x\n", ret);
2193 if(SUCCEEDED(ret)) IShellItem_Release(shellitem);
2195 lstrcpyW(fnbufW, curdirW);
2196 myPathAddBackslashW(fnbufW);
2197 lstrcatW(fnbufW, testfileW);
2199 ret = pSHCreateItemFromParsingName(fnbufW, NULL, &IID_IShellItem, (void**)&shellitem);
2200 ok(ret == S_OK, "SHCreateItemFromParsingName returned %x\n", ret);
2204 ret = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &tmp_fname);
2205 ok(ret == S_OK, "GetDisplayName returned %x\n", ret);
2208 ok(!lstrcmpW(fnbufW, tmp_fname), "strings not equal\n");
2209 CoTaskMemFree(tmp_fname);
2211 IShellItem_Release(shellitem);
2215 win_skip("No SHCreateItemFromParsingName\n");
2218 /* SHCreateItemFromIDList */
2219 if(pSHCreateItemFromIDList)
2223 /* Crashes under win7 */
2224 ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, NULL);
2227 ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, (void**)&shellitem);
2228 ok(ret == E_INVALIDARG, "SHCreateItemFromIDList returned %x\n", ret);
2230 ret = pSHCreateItemFromIDList(pidl_cwd, &IID_IShellItem, (void**)&shellitem);
2231 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2234 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2235 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2238 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2239 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2242 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2245 IPersistIDList_Release(persistidl);
2247 IShellItem_Release(shellitem);
2250 ret = pSHCreateItemFromIDList(pidl_testfile, &IID_IShellItem, (void**)&shellitem);
2251 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2254 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2255 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2258 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2259 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2262 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2265 IPersistIDList_Release(persistidl);
2267 IShellItem_Release(shellitem);
2271 win_skip("No SHCreateItemFromIDList\n");
2273 DeleteFileA(".\\testfile");
2274 pILFree(pidl_abstestfile);
2275 pILFree(pidl_testfile);
2276 pILFree(pidl_desktop);
2278 IShellFolder_Release(currentfolder);
2279 IShellFolder_Release(desktopfolder);
2282 static void test_SHGetNameFromIDList(void)
2284 IShellItem *shellitem;
2289 static const DWORD flags[] = {
2290 SIGDN_NORMALDISPLAY, SIGDN_PARENTRELATIVEPARSING,
2291 SIGDN_DESKTOPABSOLUTEPARSING,SIGDN_PARENTRELATIVEEDITING,
2292 SIGDN_DESKTOPABSOLUTEEDITING, /*SIGDN_FILESYSPATH, SIGDN_URL, */
2293 SIGDN_PARENTRELATIVEFORADDRESSBAR,SIGDN_PARENTRELATIVE, -1234};
2295 if(!pSHGetNameFromIDList)
2297 win_skip("SHGetNameFromIDList missing.\n");
2301 /* These should be available on any platform that passed the above test. */
2302 ok(pSHCreateShellItem != NULL, "SHCreateShellItem missing.\n");
2303 ok(pSHBindToParent != NULL, "SHBindToParent missing.\n");
2304 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
2305 ok(pStrRetToBufW != NULL, "StrRetToBufW missing.\n");
2309 /* Crashes under win7 */
2310 hres = pSHGetNameFromIDList(NULL, 0, NULL);
2313 hres = pSHGetNameFromIDList(NULL, 0, &name_string);
2314 ok(hres == E_INVALIDARG, "Got 0x%08x\n", hres);
2316 /* Test the desktop */
2317 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
2318 ok(hres == S_OK, "Got 0x%08x\n", hres);
2319 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2320 ok(hres == S_OK, "Got 0x%08x\n", hres);
2323 WCHAR *nameSI, *nameSH;
2324 WCHAR buf[MAX_PATH];
2325 HRESULT hrSI, hrSH, hrSF;
2330 SHGetDesktopFolder(&psf);
2331 for(i = 0; flags[i] != -1234; i++)
2333 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2334 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2335 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2336 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2337 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2338 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2340 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2341 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2345 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2347 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2349 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2351 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2352 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2354 IShellFolder_Release(psf);
2356 if(pSHGetPathFromIDListW){
2357 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2358 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2359 res = pSHGetPathFromIDListW(pidl, buf);
2360 ok(res == TRUE, "Got %d\n", res);
2361 if(SUCCEEDED(hrSI) && res)
2362 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2363 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2365 win_skip("pSHGetPathFromIDListW not available\n");
2367 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2368 todo_wine ok(hres == S_OK, "Got 0x%08x\n", hres);
2369 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2371 IShellItem_Release(shellitem);
2375 /* Test the control panel */
2376 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_CONTROLS, &pidl);
2377 ok(hres == S_OK, "Got 0x%08x\n", hres);
2378 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2379 ok(hres == S_OK, "Got 0x%08x\n", hres);
2382 WCHAR *nameSI, *nameSH;
2383 WCHAR buf[MAX_PATH];
2384 HRESULT hrSI, hrSH, hrSF;
2389 SHGetDesktopFolder(&psf);
2390 for(i = 0; flags[i] != -1234; i++)
2392 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2393 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2394 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2395 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2396 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2397 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2399 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2400 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2404 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2406 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2408 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2410 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2411 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2413 IShellFolder_Release(psf);
2415 if(pSHGetPathFromIDListW){
2416 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2417 ok(hrSI == E_INVALIDARG, "Got 0x%08x\n", hrSI);
2418 res = pSHGetPathFromIDListW(pidl, buf);
2419 ok(res == FALSE, "Got %d\n", res);
2420 if(SUCCEEDED(hrSI) && res)
2421 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2422 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2424 win_skip("pSHGetPathFromIDListW not available\n");
2426 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2427 todo_wine ok(hres == E_NOTIMPL /* Win7 */ || hres == S_OK /* Vista */,
2428 "Got 0x%08x\n", hres);
2429 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2431 IShellItem_Release(shellitem);
2436 static void test_SHGetItemFromDataObject(void)
2438 IShellFolder *psfdesktop;
2443 if(!pSHGetItemFromDataObject)
2445 win_skip("No SHGetItemFromDataObject.\n");
2451 /* Crashes under win7 */
2452 hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, NULL);
2455 hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, (void**)&psv);
2456 ok(hres == E_INVALIDARG, "got 0x%08x\n", hres);
2458 SHGetDesktopFolder(&psfdesktop);
2460 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
2461 ok(hres == S_OK, "got 0x%08x\n", hres);
2468 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
2469 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
2470 ok(hres == S_OK, "got 0x%08x\n", hres);
2473 LPITEMIDLIST apidl[5];
2476 for(count = 0; count < 5; count++)
2477 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
2482 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
2483 &IID_IDataObject, NULL, (void**)&pdo);
2484 ok(hres == S_OK, "got 0x%08x\n", hres);
2487 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2488 ok(hres == S_OK, "got 0x%08x\n", hres);
2489 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2490 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2491 ok(hres == S_OK, "got 0x%08x\n", hres);
2492 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2493 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2494 ok(hres == S_OK, "got 0x%08x\n", hres);
2495 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2496 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2497 ok(hres == S_OK, "got 0x%08x\n", hres);
2498 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2499 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2500 ok(hres == S_OK, "got 0x%08x\n", hres);
2501 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2503 IDataObject_Release(pdo);
2507 skip("No file(s) found - skipping single-file test.\n");
2511 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
2512 &IID_IDataObject, NULL, (void**)&pdo);
2513 ok(hres == S_OK, "got 0x%08x\n", hres);
2516 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2517 ok(hres == S_OK, "got 0x%08x\n", hres);
2518 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2519 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2520 ok(hres == S_OK, "got 0x%08x\n", hres);
2521 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2522 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2523 ok(hres == S_OK, "got 0x%08x\n", hres);
2524 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2525 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2526 ok(hres == S_OK, "got 0x%08x\n", hres);
2527 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2528 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2529 ok(hres == E_FAIL, "got 0x%08x\n", hres);
2530 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2531 IDataObject_Release(pdo);
2535 skip("zero or one file found - skipping multi-file test.\n");
2537 for(i = 0; i < count; i++)
2540 IEnumIDList_Release(peidl);
2543 IShellView_Release(psv);
2546 IShellFolder_Release(psfdesktop);
2549 static void test_ShellItemCompare(void)
2551 IShellItem *psi[9]; /* a\a, a\b, a\c, b\a, .. */
2552 IShellItem *psi_a = NULL, *psi_b = NULL, *psi_c = NULL;
2553 IShellFolder *psf_desktop, *psf_current;
2554 LPITEMIDLIST pidl_cwd;
2555 WCHAR curdirW[MAX_PATH];
2558 static const WCHAR filesW[][9] = {
2559 {'a','\\','a',0}, {'a','\\','b',0}, {'a','\\','c',0},
2560 {'b','\\','a',0}, {'b','\\','b',0}, {'b','\\','c',0},
2561 {'c','\\','a',0}, {'c','\\','b',0}, {'c','\\','c',0} };
2565 if(!pSHCreateShellItem)
2567 win_skip("SHCreateShellItem missing.\n");
2571 GetCurrentDirectoryW(MAX_PATH, curdirW);
2572 if(!lstrlenW(curdirW))
2574 skip("Failed to get current directory, skipping.\n");
2578 CreateDirectoryA(".\\a", NULL);
2579 CreateDirectoryA(".\\b", NULL);
2580 CreateDirectoryA(".\\c", NULL);
2581 CreateTestFile(".\\a\\a");
2582 CreateTestFile(".\\a\\b");
2583 CreateTestFile(".\\a\\c");
2584 CreateTestFile(".\\b\\a");
2585 CreateTestFile(".\\b\\b");
2586 CreateTestFile(".\\b\\c");
2587 CreateTestFile(".\\c\\a");
2588 CreateTestFile(".\\c\\b");
2589 CreateTestFile(".\\c\\c");
2591 SHGetDesktopFolder(&psf_desktop);
2592 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2593 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2594 hr = IShellFolder_BindToObject(psf_desktop, pidl_cwd, NULL, &IID_IShellFolder, (void**)&psf_current);
2595 ok(SUCCEEDED(hr), "BindToObject returned %x\n", hr);
2596 IShellFolder_Release(psf_desktop);
2598 /* Generate ShellItems for the files */
2599 ZeroMemory(&psi, sizeof(IShellItem*)*9);
2601 for(i = 0; i < 9; i++)
2603 LPITEMIDLIST pidl_testfile = NULL;
2605 hr = IShellFolder_ParseDisplayName(psf_current, NULL, NULL, (LPWSTR)filesW[i],
2606 NULL, &pidl_testfile, NULL);
2607 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2610 hr = pSHCreateShellItem(NULL, NULL, pidl_testfile, &psi[i]);
2611 ok(hr == S_OK, "Got 0x%08x\n", hr);
2612 pILFree(pidl_testfile);
2614 if(FAILED(hr)) failed = TRUE;
2618 skip("Failed to create all shellitems.\n");
2622 /* Generate ShellItems for the folders */
2623 hr = IShellItem_GetParent(psi[0], &psi_a);
2624 ok(hr == S_OK, "Got 0x%08x\n", hr);
2625 if(FAILED(hr)) failed = TRUE;
2626 hr = IShellItem_GetParent(psi[3], &psi_b);
2627 ok(hr == S_OK, "Got 0x%08x\n", hr);
2628 if(FAILED(hr)) failed = TRUE;
2629 hr = IShellItem_GetParent(psi[6], &psi_c);
2630 ok(hr == S_OK, "Got 0x%08x\n", hr);
2631 if(FAILED(hr)) failed = TRUE;
2635 skip("Failed to create shellitems.\n");
2641 /* Crashes on native (win7, winxp) */
2642 hr = IShellItem_Compare(psi_a, NULL, 0, NULL);
2643 hr = IShellItem_Compare(psi_a, psi_b, 0, NULL);
2644 hr = IShellItem_Compare(psi_a, NULL, 0, &order);
2648 for(i = 0; i < 9; i++)
2650 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_DISPLAY, &order);
2651 ok(hr == S_OK, "Got 0x%08x\n", hr);
2652 ok(order == 0, "Got order %d\n", order);
2653 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_CANONICAL, &order);
2654 ok(hr == S_OK, "Got 0x%08x\n", hr);
2655 ok(order == 0, "Got order %d\n", order);
2656 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_ALLFIELDS, &order);
2657 ok(hr == S_OK, "Got 0x%08x\n", hr);
2658 ok(order == 0, "Got order %d\n", order);
2662 /* a\b:a\a , a\b:a\c, a\b:a\b */
2663 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_DISPLAY, &order);
2664 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2665 ok(order == 1, "Got order %d\n", order);
2666 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_DISPLAY, &order);
2667 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2668 ok(order == -1, "Got order %d\n", order);
2669 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_DISPLAY, &order);
2670 ok(hr == S_OK, "Got 0x%08x\n", hr);
2671 ok(order == 0, "Got order %d\n", order);
2673 /* b\b:a\b, b\b:c\b, b\b:c\b */
2674 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_DISPLAY, &order);
2675 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2676 ok(order == 1, "Got order %d\n", order);
2677 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_DISPLAY, &order);
2678 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2679 ok(order == -1, "Got order %d\n", order);
2680 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_DISPLAY, &order);
2681 ok(hr == S_OK, "Got 0x%08x\n", hr);
2682 ok(order == 0, "Got order %d\n", order);
2684 /* b:a\a, b:a\c, b:a\b */
2685 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_DISPLAY, &order);
2686 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2687 todo_wine ok(order == 1, "Got order %d\n", order);
2688 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_DISPLAY, &order);
2689 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2690 todo_wine ok(order == 1, "Got order %d\n", order);
2691 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_DISPLAY, &order);
2692 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2693 todo_wine ok(order == 1, "Got order %d\n", order);
2695 /* b:c\a, b:c\c, b:c\b */
2696 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_DISPLAY, &order);
2697 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2698 ok(order == -1, "Got order %d\n", order);
2699 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_DISPLAY, &order);
2700 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2701 ok(order == -1, "Got order %d\n", order);
2702 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_DISPLAY, &order);
2703 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2704 ok(order == -1, "Got order %d\n", order);
2706 /* a\b:a\a , a\b:a\c, a\b:a\b */
2707 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_CANONICAL, &order);
2708 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2709 ok(order == 1, "Got order %d\n", order);
2710 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_CANONICAL, &order);
2711 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2712 ok(order == -1, "Got order %d\n", order);
2713 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_CANONICAL, &order);
2714 ok(hr == S_OK, "Got 0x%08x\n", hr);
2715 ok(order == 0, "Got order %d\n", order);
2717 /* b\b:a\b, b\b:c\b, b\b:c\b */
2718 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_CANONICAL, &order);
2719 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2720 ok(order == 1, "Got order %d\n", order);
2721 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_CANONICAL, &order);
2722 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2723 ok(order == -1, "Got order %d\n", order);
2724 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_CANONICAL, &order);
2725 ok(hr == S_OK, "Got 0x%08x\n", hr);
2726 ok(order == 0, "Got order %d\n", order);
2728 /* b:a\a, b:a\c, b:a\b */
2729 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_CANONICAL, &order);
2730 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2731 todo_wine ok(order == 1, "Got order %d\n", order);
2732 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_CANONICAL, &order);
2733 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2734 todo_wine ok(order == 1, "Got order %d\n", order);
2735 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_CANONICAL, &order);
2736 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2737 todo_wine ok(order == 1, "Got order %d\n", order);
2739 /* b:c\a, b:c\c, b:c\b */
2740 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_CANONICAL, &order);
2741 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2742 ok(order == -1, "Got order %d\n", order);
2743 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_CANONICAL, &order);
2744 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2745 ok(order == -1, "Got order %d\n", order);
2746 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_CANONICAL, &order);
2747 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2748 ok(order == -1, "Got order %d\n", order);
2751 IShellFolder_Release(psf_current);
2753 DeleteFileA(".\\a\\a");
2754 DeleteFileA(".\\a\\b");
2755 DeleteFileA(".\\a\\c");
2756 DeleteFileA(".\\b\\a");
2757 DeleteFileA(".\\b\\b");
2758 DeleteFileA(".\\b\\c");
2759 DeleteFileA(".\\c\\a");
2760 DeleteFileA(".\\c\\b");
2761 DeleteFileA(".\\c\\c");
2762 RemoveDirectoryA(".\\a");
2763 RemoveDirectoryA(".\\b");
2764 RemoveDirectoryA(".\\c");
2766 if(psi_a) IShellItem_Release(psi_a);
2767 if(psi_b) IShellItem_Release(psi_b);
2768 if(psi_c) IShellItem_Release(psi_c);
2770 for(i = 0; i < 9; i++)
2771 if(psi[i]) IShellItem_Release(psi[i]);
2774 /**************************************************************/
2775 /* IUnknown implementation for counting QueryInterface calls. */
2777 const IUnknownVtbl *lpVtbl;
2785 static HRESULT WINAPI unk_fnQueryInterface(IUnknown *iunk, REFIID riid, void** punk)
2787 IUnknownImpl *This = (IUnknownImpl*)iunk;
2789 for(i = found = 0; This->ifaces[i].id != NULL; i++)
2791 if(IsEqualIID(This->ifaces[i].id, riid))
2793 This->ifaces[i].count++;
2800 return E_NOINTERFACE;
2803 static ULONG WINAPI unk_fnAddRef(IUnknown *iunk)
2808 static ULONG WINAPI unk_fnRelease(IUnknown *iunk)
2813 static const IUnknownVtbl vt_IUnknown = {
2814 unk_fnQueryInterface,
2819 static void test_SHGetIDListFromObject(void)
2821 IUnknownImpl *punkimpl;
2822 IShellFolder *psfdesktop;
2824 LPITEMIDLIST pidl, pidl_desktop;
2827 struct if_count ifaces[] =
2828 { {&IID_IPersistIDList, 0},
2829 {&IID_IPersistFolder2, 0},
2830 {&IID_IDataObject, 0},
2831 {&IID_IParentAndItem, 0},
2832 {&IID_IFolderView, 0},
2835 if(!pSHGetIDListFromObject)
2837 win_skip("SHGetIDListFromObject missing.\n");
2841 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
2845 /* Crashes native */
2846 pSHGetIDListFromObject(NULL, NULL);
2847 pSHGetIDListFromObject((void*)0xDEADBEEF, NULL);
2850 hres = pSHGetIDListFromObject(NULL, &pidl);
2851 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
2853 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
2854 punkimpl->lpVtbl = &vt_IUnknown;
2855 punkimpl->ifaces = ifaces;
2856 punkimpl->unknown = 0;
2858 hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
2859 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
2860 ok(ifaces[0].count, "interface not requested.\n");
2861 ok(ifaces[1].count, "interface not requested.\n");
2862 ok(ifaces[2].count, "interface not requested.\n");
2864 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
2865 "interface not requested.\n");
2866 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
2867 "interface not requested.\n");
2869 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
2870 HeapFree(GetProcessHeap(), 0, punkimpl);
2872 pidl_desktop = NULL;
2873 pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
2874 ok(pidl_desktop != NULL, "Failed to get desktop pidl.\n");
2876 SHGetDesktopFolder(&psfdesktop);
2878 /* Test IShellItem */
2879 if(pSHCreateShellItem)
2881 IShellItem *shellitem;
2882 hres = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
2883 ok(hres == S_OK, "got 0x%08x\n", hres);
2886 hres = pSHGetIDListFromObject((IUnknown*)shellitem, &pidl);
2887 ok(hres == S_OK, "got 0x%08x\n", hres);
2890 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
2893 IShellItem_Release(shellitem);
2897 skip("no SHCreateShellItem.\n");
2899 /* Test IShellFolder */
2900 hres = pSHGetIDListFromObject((IUnknown*)psfdesktop, &pidl);
2901 ok(hres == S_OK, "got 0x%08x\n", hres);
2904 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
2908 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
2909 ok(hres == S_OK, "got 0x%08x\n", hres);
2916 /* Test IFolderView */
2917 hres = pSHGetIDListFromObject((IUnknown*)psv, &pidl);
2918 ok(hres == S_OK, "got 0x%08x\n", hres);
2921 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
2925 /* Test IDataObject */
2926 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
2927 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
2928 ok(hres == S_OK, "got 0x%08x\n", hres);
2931 LPITEMIDLIST apidl[5];
2933 for(count = 0; count < 5; count++)
2934 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
2939 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
2940 &IID_IDataObject, NULL, (void**)&pdo);
2941 ok(hres == S_OK, "got 0x%08x\n", hres);
2944 pidl = (void*)0xDEADBEEF;
2945 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
2946 ok(hres == S_OK, "got 0x%08x\n", hres);
2947 ok(pidl != NULL, "pidl is NULL.\n");
2948 ok(ILIsEqual(pidl, apidl[0]), "pidl not equal.\n");
2951 IDataObject_Release(pdo);
2955 skip("No files found - skipping single-file test.\n");
2959 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
2960 &IID_IDataObject, NULL, (void**)&pdo);
2961 ok(hres == S_OK, "got 0x%08x\n", hres);
2964 pidl = (void*)0xDEADBEEF;
2965 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
2966 ok(hres == E_NOINTERFACE || hres == E_FAIL /*Vista*/,
2967 "got 0x%08x\n", hres);
2968 ok(pidl == NULL, "pidl is not NULL.\n");
2970 IDataObject_Release(pdo);
2974 skip("zero or one file found - skipping multi-file test.\n");
2976 for(i = 0; i < count; i++)
2979 IEnumIDList_Release(peidl);
2982 IShellView_Release(psv);
2985 IShellFolder_Release(psfdesktop);
2986 pILFree(pidl_desktop);
2989 static void test_SHGetItemFromObject(void)
2991 IUnknownImpl *punkimpl;
2992 IShellFolder *psfdesktop;
2997 struct if_count ifaces[] =
2998 { {&IID_IPersistIDList, 0},
2999 {&IID_IPersistFolder2, 0},
3000 {&IID_IDataObject, 0},
3001 {&IID_IParentAndItem, 0},
3002 {&IID_IFolderView, 0},
3005 if(!pSHGetItemFromObject)
3007 skip("No SHGetItemFromObject.\n");
3011 SHGetDesktopFolder(&psfdesktop);
3015 /* Crashes with Windows 7 */
3016 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IUnknown, NULL);
3017 hres = pSHGetItemFromObject(NULL, &IID_IUnknown, NULL);
3018 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, NULL, (void**)&punk);
3021 hres = pSHGetItemFromObject(NULL, &IID_IUnknown, (void**)&punk);
3022 ok(hres == E_NOINTERFACE, "Got 0x%08x\n", hres);
3024 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
3025 punkimpl->lpVtbl = &vt_IUnknown;
3026 punkimpl->ifaces = ifaces;
3027 punkimpl->unknown = 0;
3029 /* The same as SHGetIDListFromObject */
3030 hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
3031 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3032 ok(ifaces[0].count, "interface not requested.\n");
3033 ok(ifaces[1].count, "interface not requested.\n");
3034 ok(ifaces[2].count, "interface not requested.\n");
3036 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3037 "interface not requested.\n");
3038 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3039 "interface not requested.\n");
3041 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3042 HeapFree(GetProcessHeap(), 0, punkimpl);
3044 /* Test IShellItem */
3045 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IShellItem, (void**)&psi);
3046 ok(hres == S_OK, "Got 0x%08x\n", hres);
3050 hres = pSHGetItemFromObject((IUnknown*)psi, &IID_IShellItem, (void**)&psi2);
3051 ok(hres == S_OK, "Got 0x%08x\n", hres);
3055 ok(psi == psi2, "Different instances (%p != %p).\n", psi, psi2);
3056 IShellItem_Release(psi2);
3058 IShellItem_Release(psi);
3061 IShellFolder_Release(psfdesktop);
3064 static void test_SHCreateShellItemArray(void)
3066 IShellFolder *pdesktopsf, *psf;
3067 IShellItemArray *psia;
3070 WCHAR cTestDirW[MAX_PATH];
3071 LPITEMIDLIST pidl_testdir, pidl;
3072 static const WCHAR testdirW[] = {'t','e','s','t','d','i','r',0};
3074 if(!pSHCreateShellItemArray) {
3075 skip("No pSHCreateShellItemArray!\n");
3079 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
3083 /* Crashes under native */
3084 pSHCreateShellItemArray(NULL, NULL, 0, NULL, NULL);
3085 pSHCreateShellItemArray(NULL, NULL, 1, NULL, NULL);
3086 pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, NULL);
3087 pSHCreateShellItemArray(pidl, NULL, 0, NULL, NULL);
3090 hr = pSHCreateShellItemArray(NULL, NULL, 0, NULL, &psia);
3091 ok(hr == E_POINTER, "got 0x%08x\n", hr);
3093 SHGetDesktopFolder(&pdesktopsf);
3094 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, &psia);
3095 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3097 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 1, NULL, &psia);
3098 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3100 pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
3101 hr = pSHCreateShellItemArray(pidl, NULL, 0, NULL, &psia);
3102 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3105 GetCurrentDirectoryW(MAX_PATH, cTestDirW);
3106 myPathAddBackslashW(cTestDirW);
3107 lstrcatW(cTestDirW, testdirW);
3109 CreateFilesFolders();
3111 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, cTestDirW, NULL, &pidl_testdir, 0);
3112 ok(hr == S_OK, "got 0x%08x\n", hr);
3115 hr = IShellFolder_BindToObject(pdesktopsf, pidl_testdir, NULL, (REFIID)&IID_IShellFolder,
3117 ok(hr == S_OK, "Got 0x%08x\n", hr);
3119 IShellFolder_Release(pdesktopsf);
3123 skip("Failed to set up environment for SHCreateShellItemArray tests.\n");
3124 pILFree(pidl_testdir);
3129 hr = IShellFolder_EnumObjects(psf, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &peidl);
3130 ok(hr == S_OK, "Got %08x\n", hr);
3133 LPITEMIDLIST apidl[5];
3134 UINT done, numitems, i;
3136 for(done = 0; done < 5; done++)
3137 if(IEnumIDList_Next(peidl, 1, &apidl[done], NULL) != S_OK)
3139 ok(done == 5, "Got %d pidls\n", done);
3140 IEnumIDList_Release(peidl);
3142 /* Create a ShellItemArray */
3143 hr = pSHCreateShellItemArray(NULL, psf, done, (LPCITEMIDLIST*)apidl, &psia);
3144 ok(hr == S_OK, "Got 0x%08x\n", hr);
3151 /* Crashes in Windows 7 */
3152 hr = IShellItemArray_GetCount(psia, NULL);
3155 IShellItemArray_GetCount(psia, &numitems);
3156 ok(numitems == done, "Got %d, expected %d\n", numitems, done);
3158 hr = IShellItemArray_GetItemAt(psia, numitems, &psi);
3159 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3161 /* Compare all the items */
3162 for(i = 0; i < numitems; i++)
3164 LPITEMIDLIST pidl_abs;
3165 pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3167 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3168 ok(hr == S_OK, "(%d) Failed with 0x%08x\n", i, hr);
3171 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3172 ok(hr == S_OK, "Got 0x%08x\n", hr);
3175 ok(ILIsEqual(pidl_abs, pidl), "Pidl not equal.\n");
3178 IShellItem_Release(psi);
3182 for(i = 0; i < done; i++)
3184 IShellItemArray_Release(psia);
3188 /* SHCreateShellItemArrayFromShellItem */
3189 if(pSHCreateShellItemArrayFromShellItem)
3195 /* Crashes under Windows 7 */
3196 hr = pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, NULL);
3197 hr = pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, (void**)&psia);
3198 hr = pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, NULL);
3201 hr = pSHCreateItemFromIDList(pidl_testdir, &IID_IShellItem, (void**)&psi);
3202 ok(hr == S_OK, "Got 0x%08x\n", hr);
3205 hr = pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, (void**)&psia);
3206 ok(hr == S_OK, "Got 0x%08x\n", hr);
3211 hr = IShellItemArray_GetCount(psia, &count);
3212 ok(hr == S_OK, "Got 0x%08x\n", hr);
3213 ok(count == 1, "Got count %d\n", count);
3214 hr = IShellItemArray_GetItemAt(psia, 0, &psi2);
3215 ok(hr == S_OK, "Got 0x%08x\n", hr);
3217 ok(psi != psi2, "ShellItems are of the same instance.\n");
3220 LPITEMIDLIST pidl1, pidl2;
3221 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl1);
3222 ok(hr == S_OK, "Got 0x%08x\n", hr);
3223 ok(pidl1 != NULL, "pidl1 was null.\n");
3224 hr = pSHGetIDListFromObject((IUnknown*)psi2, &pidl2);
3225 ok(hr == S_OK, "Got 0x%08x\n", hr);
3226 ok(pidl2 != NULL, "pidl2 was null.\n");
3227 ok(ILIsEqual(pidl1, pidl2), "pidls not equal.\n");
3230 IShellItem_Release(psi2);
3232 hr = IShellItemArray_GetItemAt(psia, 1, &psi2);
3233 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3234 IShellItemArray_Release(psia);
3236 IShellItem_Release(psi);
3240 skip("No SHCreateShellItemArrayFromShellItem.\n");
3242 if(pSHCreateShellItemArrayFromDataObject)
3248 /* Crashes under Windows 7 */
3249 hr = pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, NULL);
3251 hr = pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, (void**)&psia);
3252 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3254 hr = IShellFolder_CreateViewObject(psf, NULL, &IID_IShellView, (void**)&psv);
3255 ok(hr == S_OK, "got 0x%08x\n", hr);
3262 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3263 hr = IShellFolder_EnumObjects(psf, NULL, enum_flags, &peidl);
3264 ok(hr == S_OK, "got 0x%08x\n", hr);
3267 LPITEMIDLIST apidl[5];
3270 for(count = 0; count < 5; count++)
3271 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3273 ok(count == 5, "Got %d\n", count);
3277 hr = IShellFolder_GetUIObjectOf(psf, NULL, count, (LPCITEMIDLIST*)apidl,
3278 &IID_IDataObject, NULL, (void**)&pdo);
3279 ok(hr == S_OK, "Got 0x%08x\n", hr);
3282 hr = pSHCreateShellItemArrayFromDataObject(pdo, &IID_IShellItemArray,
3284 ok(hr == S_OK, "Got 0x%08x\n", hr);
3288 hr = IShellItemArray_GetCount(psia, &count_sia);
3289 ok(count_sia == count, "Counts differ (%d, %d)\n", count, count_sia);
3290 for(i = 0; i < count_sia; i++)
3292 LPITEMIDLIST pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3294 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3295 ok(hr == S_OK, "Got 0x%08x\n", hr);
3299 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3300 ok(hr == S_OK, "Got 0x%08x\n", hr);
3301 ok(pidl != NULL, "pidl as NULL.\n");
3302 ok(ILIsEqual(pidl, pidl_abs), "pidls differ.\n");
3304 IShellItem_Release(psi);
3309 IShellItemArray_Release(psia);
3312 IDataObject_Release(pdo);
3314 for(i = 0; i < count; i++)
3318 skip("No files found - skipping test.\n");
3320 IEnumIDList_Release(peidl);
3322 IShellView_Release(psv);
3326 skip("No SHCreateShellItemArrayFromDataObject.\n");
3328 IShellFolder_Release(psf);
3329 pILFree(pidl_testdir);
3333 static void test_ShellItemBindToHandler(void)
3336 LPITEMIDLIST pidl_desktop;
3339 if(!pSHCreateShellItem)
3341 skip("SHCreateShellItem missing.\n");
3345 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3346 ok(hr == S_OK, "Got 0x%08x\n", hr);
3349 hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
3350 ok(hr == S_OK, "Got 0x%08x\n", hr);
3354 IPersistFolder2 *ppf2;
3359 /* Crashes under Windows 7 */
3360 hr = IShellItem_BindToHandler(psi, NULL, NULL, NULL, NULL);
3361 hr = IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, NULL);
3363 hr = IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, (void**)&punk);
3364 ok(hr == MK_E_NOOBJECT, "Got 0x%08x\n", hr);
3367 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IShellFolder, (void**)&punk);
3368 ok(hr == S_OK, "Got 0x%08x\n", hr);
3369 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3370 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IPersistFolder2, (void**)&ppf2);
3371 ok(hr == S_OK, "Got 0x%08x\n", hr);
3374 LPITEMIDLIST pidl_tmp;
3375 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl_tmp);
3376 ok(hr == S_OK, "Got 0x%08x\n", hr);
3379 ok(ILIsEqual(pidl_desktop, pidl_tmp), "Pidl not equal (%p, %p)\n", pidl_desktop, pidl_tmp);
3382 IPersistFolder2_Release(ppf2);
3385 /* BHID_SFUIObject */
3386 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IDataObject, (void**)&punk);
3387 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3388 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3389 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IContextMenu, (void**)&punk);
3390 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3391 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3393 /* BHID_DataObject */
3394 hr = IShellItem_BindToHandler(psi, NULL, &BHID_DataObject, &IID_IDataObject, (void**)&punk);
3395 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3396 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3400 /* BHID_SFViewObject */
3401 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellView, (void**)&punk);
3402 ok(hr == S_OK, "Got 0x%08x\n", hr);
3403 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3404 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellFolderView, (void**)&punk);
3405 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3406 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3409 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IStream, (void**)&punk);
3410 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3411 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3412 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IUnknown, (void**)&punk);
3413 ok(hr == S_OK, "Got 0x%08x\n", hr);
3414 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3417 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IStream, (void**)&punk);
3418 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3419 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3420 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IUnknown, (void**)&punk);
3421 ok(hr == S_OK, "Got 0x%08x\n", hr);
3422 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3424 /* BHID_StorageEnum */
3425 hr = IShellItem_BindToHandler(psi, NULL, &BHID_StorageEnum, &IID_IEnumShellItems, (void**)&punk);
3426 ok(hr == S_OK, "Got 0x%08x\n", hr);
3427 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3430 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_IUnknown, (void**)&punk);
3431 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3432 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3434 /* BHID_EnumItems */
3435 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumItems, &IID_IEnumShellItems, (void**)&punk);
3436 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3437 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3440 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Filter, &IID_IUnknown, (void**)&punk);
3441 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3442 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3444 /* BHID_LinkTargetItem */
3445 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IShellItem, (void**)&punk);
3446 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3447 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3448 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IUnknown, (void**)&punk);
3449 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3450 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3452 /* BHID_PropertyStore */
3453 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStore, (void**)&punk);
3454 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3455 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3456 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStoreFactory, (void**)&punk);
3457 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3458 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3460 /* BHID_ThumbnailHandler */
3461 hr = IShellItem_BindToHandler(psi, NULL, &BHID_ThumbnailHandler, &IID_IUnknown, (void**)&punk);
3462 ok(hr == E_INVALIDARG || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3463 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3465 /* BHID_AssociationArray */
3466 hr = IShellItem_BindToHandler(psi, NULL, &BHID_AssociationArray, &IID_IQueryAssociations, (void**)&punk);
3467 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3468 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3470 /* BHID_EnumAssocHandlers */
3471 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumAssocHandlers, &IID_IUnknown, (void**)&punk);
3472 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3473 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3476 IShellItem_Release(psi);
3479 skip("Failed to create ShellItem.\n");
3481 pILFree(pidl_desktop);
3484 static void test_SHParseDisplayName(void)
3486 LPITEMIDLIST pidl1, pidl2;
3487 IShellFolder *desktop;
3488 WCHAR dirW[MAX_PATH];
3493 if (!pSHParseDisplayName)
3495 win_skip("SHParseDisplayName isn't available\n");
3501 /* crashes on native */
3502 hr = pSHParseDisplayName(NULL, NULL, NULL, 0, NULL);
3504 hr = pSHParseDisplayName(nameW, NULL, NULL, 0, NULL);
3507 pidl1 = (LPITEMIDLIST)0xdeadbeef;
3508 hr = pSHParseDisplayName(NULL, NULL, &pidl1, 0, NULL);
3509 ok(broken(hr == E_OUTOFMEMORY) /* < Vista */ ||
3510 hr == E_INVALIDARG, "failed %08x\n", hr);
3511 ok(pidl1 == 0, "expected null ptr, got %p\n", pidl1);
3515 hr = pSHParseDisplayName(nameW, NULL, &pidl1, 0, NULL);
3516 ok(hr == S_OK, "failed %08x\n", hr);
3517 hr = SHGetDesktopFolder(&desktop);
3518 ok(hr == S_OK, "failed %08x\n", hr);
3519 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, nameW, NULL, &pidl2, NULL);
3520 ok(hr == S_OK, "failed %08x\n", hr);
3521 ret = pILIsEqual(pidl1, pidl2);
3522 ok(ret == TRUE, "expected equal idls\n");
3527 GetWindowsDirectoryW( dirW, MAX_PATH );
3529 hr = pSHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
3530 ok(hr == S_OK, "failed %08x\n", hr);
3531 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, dirW, NULL, &pidl2, NULL);
3532 ok(hr == S_OK, "failed %08x\n", hr);
3534 ret = pILIsEqual(pidl1, pidl2);
3535 ok(ret == TRUE, "expected equal idls\n");
3539 IShellFolder_Release(desktop);
3542 static void test_desktop_IPersist(void)
3544 IShellFolder *desktop;
3546 IPersistFolder2 *ppf2;
3550 hr = SHGetDesktopFolder(&desktop);
3551 ok(hr == S_OK, "failed %08x\n", hr);
3553 hr = IShellFolder_QueryInterface(desktop, &IID_IPersist, (void**)&persist);
3554 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* NT4, W9X */, "failed %08x\n", hr);
3560 /* crashes on native */
3561 hr = IPersist_GetClassID(persist, NULL);
3563 memset(&clsid, 0, sizeof(clsid));
3564 hr = IPersist_GetClassID(persist, &clsid);
3565 ok(hr == S_OK, "failed %08x\n", hr);
3566 ok(IsEqualIID(&CLSID_ShellDesktop, &clsid), "Expected CLSID_ShellDesktop\n");
3567 IPersist_Release(persist);
3570 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder2, (void**)&ppf2);
3571 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* pre-Vista */, "failed %08x\n", hr);
3574 IPersistFolder *ppf;
3576 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder, (void**)&ppf);
3577 ok(hr == S_OK, "IID_IPersistFolder2 without IID_IPersistFolder.\n");
3579 IPersistFolder_Release(ppf);
3582 hr = IPersistFolder2_Initialize(ppf2, NULL);
3583 ok(hr == S_OK, "got %08x\n", hr);
3587 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl);
3588 ok(hr == S_OK, "got %08x\n", hr);
3589 ok(pidl != NULL, "pidl was NULL.\n");
3590 if(SUCCEEDED(hr)) pILFree(pidl);
3592 IPersistFolder2_Release(ppf2);
3595 IShellFolder_Release(desktop);
3598 static void test_GetUIObject(void)
3600 IShellFolder *psf_desktop;
3604 WCHAR path[MAX_PATH];
3605 const WCHAR filename[] =
3606 {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
3608 if(!pSHBindToParent)
3610 win_skip("SHBindToParent missing.\n");
3614 GetCurrentDirectoryW(MAX_PATH, path);
3617 skip("GetCurrentDirectoryW returned an empty string.\n");
3620 lstrcatW(path, filename);
3621 SHGetDesktopFolder(&psf_desktop);
3623 CreateFilesFolders();
3625 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, path, NULL, &pidl, 0);
3626 ok(hr == S_OK || broken(hr == E_FAIL) /* WinME */, "Got 0x%08x\n", hr);
3630 LPCITEMIDLIST pidl_child;
3631 hr = pSHBindToParent(pidl, &IID_IShellFolder, (void**)&psf, &pidl_child);
3632 ok(hr == S_OK, "Got 0x%08x\n", hr);
3635 hr = IShellFolder_GetUIObjectOf(psf, NULL, 1, (LPCITEMIDLIST*)&pidl_child,
3636 &IID_IContextMenu, NULL, (void**)&pcm);
3637 ok(hr == S_OK, "Got 0x%08x\n", hr);
3640 HMENU hmenu = CreatePopupMenu();
3641 INT max_id, max_id_check;
3643 const int id_upper_limit = 32767;
3644 hr = IContextMenu_QueryContextMenu(pcm, hmenu, 0, 0, id_upper_limit, CMF_NORMAL);
3645 ok(SUCCEEDED(hr), "Got 0x%08x\n", hr);
3646 max_id = HRESULT_CODE(hr) - 1; /* returns max_id + 1 */
3647 ok(max_id <= id_upper_limit, "Got %d\n", max_id);
3648 count = GetMenuItemCount(hmenu);
3649 ok(count, "Got %d\n", count);
3652 for(i = 0; i < count; i++)
3656 ZeroMemory(&mii, sizeof(MENUITEMINFOA));
3657 mii.cbSize = sizeof(MENUITEMINFOA);
3658 mii.fMask = MIIM_ID | MIIM_FTYPE;
3661 res = GetMenuItemInfoA(hmenu, i, TRUE, &mii);
3662 ok(res, "Failed (last error: %d).\n", GetLastError());
3664 ok( (mii.wID <= id_upper_limit) || (mii.fType & MFT_SEPARATOR),
3665 "Got non-separator ID out of range: %d (type: %x)\n", mii.wID, mii.fType);
3666 if(!(mii.fType & MFT_SEPARATOR))
3667 max_id_check = (mii.wID>max_id_check)?mii.wID:max_id_check;
3669 ok((max_id_check == max_id) ||
3670 (max_id_check == max_id-1 /* Win 7 */),
3671 "Not equal (or near equal), got %d and %d\n", max_id_check, max_id);
3673 #define is_win2k() (pSHGetFolderPathA && !pSHGetFolderPathAndSubDirA)
3675 if(count && !is_win2k()) /* Test is interactive on w2k, so skip */
3677 CMINVOKECOMMANDINFO cmi;
3678 ZeroMemory(&cmi, sizeof(CMINVOKECOMMANDINFO));
3679 cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
3681 /* Attempt to execute a nonexistent command */
3682 cmi.lpVerb = MAKEINTRESOURCEA(9999);
3683 hr = IContextMenu_InvokeCommand(pcm, &cmi);
3684 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3686 cmi.lpVerb = "foobar_wine_test";
3687 hr = IContextMenu_InvokeCommand(pcm, &cmi);
3688 ok( (hr == E_INVALIDARG) || (hr == E_FAIL /* Win7 */) ||
3689 (hr == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION) /* Vista */),
3690 "Got 0x%08x\n", hr);
3695 IContextMenu_Release(pcm);
3697 IShellFolder_Release(psf);
3699 if(pILFree) pILFree(pidl);
3702 IShellFolder_Release(psf_desktop);
3706 #define verify_pidl(i,p) r_verify_pidl(__LINE__, i, p)
3707 static void r_verify_pidl(unsigned l, LPCITEMIDLIST pidl, const WCHAR *path)
3709 LPCITEMIDLIST child;
3710 IShellFolder *parent;
3714 if(!pSHBindToParent){
3715 win_skip("SHBindToParent is not available, not performing full PIDL verification\n");
3717 ok_(__FILE__,l)(pidl != NULL, "Expected PIDL to be non-NULL\n");
3719 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
3725 ok_(__FILE__,l)(0, "didn't get expected path (%s), instead: NULL\n", wine_dbgstr_w(path));
3729 hr = pSHBindToParent(pidl, &IID_IShellFolder, (LPVOID*)&parent, &child);
3730 ok_(__FILE__,l)(hr == S_OK, "SHBindToParent failed: 0x%08x\n", hr);
3734 hr = IShellFolder_GetDisplayNameOf(parent, child, SHGDN_FORPARSING, &filename);
3735 ok_(__FILE__,l)(hr == S_OK, "GetDisplayNameOf failed: 0x%08x\n", hr);
3737 IShellFolder_Release(parent);
3741 ok_(__FILE__,l)(filename.uType == STRRET_WSTR || filename.uType == STRRET_CSTR,
3742 "Got unexpected string type: %d\n", filename.uType);
3743 if(filename.uType == STRRET_WSTR){
3744 ok_(__FILE__,l)(lstrcmpW(path, U(filename).pOleStr) == 0,
3745 "didn't get expected path (%s), instead: %s\n",
3746 wine_dbgstr_w(path), wine_dbgstr_w(U(filename).pOleStr));
3747 }else if(filename.uType == STRRET_CSTR){
3748 ok_(__FILE__,l)(strcmp_wa(path, U(filename).cStr) == 0,
3749 "didn't get expected path (%s), instead: %s\n",
3750 wine_dbgstr_w(path), U(filename).cStr);
3753 IShellFolder_Release(parent);
3755 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
3758 static void test_SHSimpleIDListFromPath(void)
3760 const WCHAR adirW[] = {'C',':','\\','s','i','d','l','f','p','d','i','r',0};
3761 const CHAR adirA[] = "C:\\sidlfpdir";
3762 BOOL br, is_unicode = !(GetVersion() & 0x80000000);
3764 LPITEMIDLIST pidl = NULL;
3766 if(!pSHSimpleIDListFromPathAW){
3767 win_skip("SHSimpleIDListFromPathAW not available\n");
3771 br = CreateDirectoryA(adirA, NULL);
3772 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
3775 pidl = pSHSimpleIDListFromPathAW(adirW);
3777 pidl = pSHSimpleIDListFromPathAW(adirA);
3778 verify_pidl(pidl, adirW);
3781 br = RemoveDirectoryA(adirA);
3782 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
3785 pidl = pSHSimpleIDListFromPathAW(adirW);
3787 pidl = pSHSimpleIDListFromPathAW(adirA);
3788 verify_pidl(pidl, adirW);
3792 /* IFileSystemBindData impl */
3793 static HRESULT WINAPI fsbd_QueryInterface(IFileSystemBindData *fsbd,
3794 REFIID riid, void **ppv)
3796 if(IsEqualIID(riid, &IID_IFileSystemBindData) ||
3797 IsEqualIID(riid, &IID_IUnknown)){
3801 return E_NOINTERFACE;
3804 static ULONG WINAPI fsbd_AddRef(IFileSystemBindData *fsbd)
3809 static ULONG WINAPI fsbd_Release(IFileSystemBindData *fsbd)
3814 static HRESULT WINAPI fsbd_SetFindData(IFileSystemBindData *fsbd,
3815 const WIN32_FIND_DATAW *pfd)
3817 ok(0, "SetFindData called\n");
3821 static HRESULT WINAPI fsbd_GetFindData_nul(IFileSystemBindData *fsbd,
3822 WIN32_FIND_DATAW *pfd)
3824 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
3828 static HRESULT WINAPI fsbd_GetFindData_junk(IFileSystemBindData *fsbd,
3829 WIN32_FIND_DATAW *pfd)
3831 memset(pfd, 0xdeadbeef, sizeof(WIN32_FIND_DATAW));
3835 static HRESULT WINAPI fsbd_GetFindData_invalid(IFileSystemBindData *fsbd,
3836 WIN32_FIND_DATAW *pfd)
3838 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
3839 *pfd->cFileName = 'a';
3840 *pfd->cAlternateFileName = 'a';
3844 static HRESULT WINAPI fsbd_GetFindData_valid(IFileSystemBindData *fsbd,
3845 WIN32_FIND_DATAW *pfd)
3847 static const WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
3848 HANDLE handle = FindFirstFileW(adirW, pfd);
3853 static HRESULT WINAPI fsbd_GetFindData_fail(IFileSystemBindData *fsbd,
3854 WIN32_FIND_DATAW *pfd)
3859 static IFileSystemBindDataVtbl fsbdVtbl = {
3860 fsbd_QueryInterface,
3867 static IFileSystemBindData fsbd = { &fsbdVtbl };
3869 static void test_ParseDisplayNamePBC(void)
3871 WCHAR wFileSystemBindData[] =
3872 {'F','i','l','e',' ','S','y','s','t','e','m',' ','B','i','n','d',' ','D','a','t','a',0};
3873 WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
3874 const HRESULT exp_err = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
3881 /* Check if we support WCHAR functions */
3882 SetLastError(0xdeadbeef);
3883 lstrcmpiW(adirW, adirW);
3884 if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED){
3885 win_skip("Most W-calls are not implemented\n");
3889 hres = SHGetDesktopFolder(&psf);
3890 ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
3892 win_skip("Failed to get IShellFolder, can't run tests\n");
3896 /* fails on unknown dir with no IBindCtx */
3897 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, adirW, NULL, &pidl, NULL);
3898 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
3899 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
3901 /* fails on unknown dir with IBindCtx with no IFileSystemBindData */
3902 hres = CreateBindCtx(0, &pbc);
3903 ok(hres == S_OK, "CreateBindCtx failed: 0x%08x\n", hres);
3905 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3906 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
3907 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
3909 /* unknown dir with IBindCtx with IFileSystemBindData */
3910 hres = IBindCtx_RegisterObjectParam(pbc, wFileSystemBindData, (IUnknown*)&fsbd);
3911 ok(hres == S_OK, "RegisterObjectParam failed: 0x%08x\n", hres);
3913 /* return E_FAIL from GetFindData */
3914 pidl = (ITEMIDLIST*)0xdeadbeef;
3915 fsbdVtbl.GetFindData = fsbd_GetFindData_fail;
3916 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3917 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
3918 "ParseDisplayName failed: 0x%08x\n", hres);
3919 if(SUCCEEDED(hres)){
3920 verify_pidl(pidl, adirW);
3924 /* set FIND_DATA struct to NULLs */
3925 pidl = (ITEMIDLIST*)0xdeadbeef;
3926 fsbdVtbl.GetFindData = fsbd_GetFindData_nul;
3927 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3928 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
3929 "ParseDisplayName failed: 0x%08x\n", hres);
3930 if(SUCCEEDED(hres)){
3931 verify_pidl(pidl, adirW);
3935 /* set FIND_DATA struct to junk */
3936 pidl = (ITEMIDLIST*)0xdeadbeef;
3937 fsbdVtbl.GetFindData = fsbd_GetFindData_junk;
3938 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3939 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
3940 "ParseDisplayName failed: 0x%08x\n", hres);
3941 if(SUCCEEDED(hres)){
3942 verify_pidl(pidl, adirW);
3946 /* set FIND_DATA struct to invalid data */
3947 pidl = (ITEMIDLIST*)0xdeadbeef;
3948 fsbdVtbl.GetFindData = fsbd_GetFindData_invalid;
3949 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3950 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
3951 "ParseDisplayName failed: 0x%08x\n", hres);
3952 if(SUCCEEDED(hres)){
3953 verify_pidl(pidl, adirW);
3957 /* set FIND_DATA struct to valid data */
3958 pidl = (ITEMIDLIST*)0xdeadbeef;
3959 fsbdVtbl.GetFindData = fsbd_GetFindData_valid;
3960 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3961 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
3962 "ParseDisplayName failed: 0x%08x\n", hres);
3963 if(SUCCEEDED(hres)){
3964 verify_pidl(pidl, adirW);
3968 IBindCtx_Release(pbc);
3969 IShellFolder_Release(psf);
3972 static const CHAR testwindow_class[] = "testwindow";
3973 #define WM_USER_NOTIFY (WM_APP+1)
3979 const WCHAR *path_1;
3980 const WCHAR *path_2;
3983 static LRESULT CALLBACK testwindow_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
3985 UINT signal = (UINT)lparam;
3988 case WM_USER_NOTIFY:
3989 if(exp_data.exp_notify){
3990 LPCITEMIDLIST *pidls = (LPCITEMIDLIST*)wparam;
3992 ok(exp_data.signal == signal,
3993 "%s: expected notification type %x, got: %x\n",
3994 exp_data.id, exp_data.signal, signal);
3996 trace("verifying pidls for: %s\n", exp_data.id);
3997 verify_pidl(pidls[0], exp_data.path_1);
3998 verify_pidl(pidls[1], exp_data.path_2);
4000 exp_data.exp_notify = FALSE;
4002 ok(exp_data.exp_notify, "Didn't expect a WM_USER_NOTIFY message (event: %x)\n", signal);
4005 return DefWindowProc(hwnd, msg, wparam, lparam);
4008 static void register_testwindow_class(void)
4013 ZeroMemory(&cls, sizeof(cls));
4014 cls.cbSize = sizeof(cls);
4016 cls.lpfnWndProc = testwindow_wndproc;
4017 cls.hInstance = GetModuleHandleA(NULL);
4018 cls.lpszClassName = testwindow_class;
4021 ret = RegisterClassExA(&cls);
4022 ok(ret != 0, "RegisterClassExA failed: %d\n", GetLastError());
4025 /* SHCNF_FLUSH doesn't seem to work as advertised for SHCNF_PATHA, so we
4026 * have to poll repeatedly for the message to appear */
4027 static void do_events(void)
4030 while (exp_data.exp_notify && (c++ < 10)){
4032 while(PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)){
4033 TranslateMessage(&msg);
4034 DispatchMessageA(&msg);
4036 if(exp_data.exp_notify)
4039 trace("%s: took %d tries\n", exp_data.id, c);
4042 static void test_SHChangeNotify(void)
4047 BOOL br, has_unicode;
4048 SHChangeNotifyEntry entries[1];
4049 const CHAR root_dirA[] = "C:\\shell32_cn_test";
4050 const WCHAR root_dirW[] = {'C',':','\\','s','h','e','l','l','3','2','_','c','n','_','t','e','s','t',0};
4051 const CHAR test_dirA[] = "C:\\shell32_cn_test\\test";
4052 const WCHAR test_dirW[] = {'C',':','\\','s','h','e','l','l','3','2','_','c','n','_','t','e','s','t','\\','t','e','s','t',0};
4054 CreateDirectoryW(NULL, NULL);
4055 has_unicode = !(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED);
4057 /* set up the root directory & window */
4058 br = CreateDirectoryA(root_dirA, NULL);
4059 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
4061 register_testwindow_class();
4063 wnd = CreateWindowExA(0, testwindow_class, testwindow_class, 0,
4064 CW_USEDEFAULT, CW_USEDEFAULT, 130, 105,
4065 NULL, NULL, GetModuleHandleA(NULL), 0);
4066 ok(wnd != NULL, "Failed to make a window\n");
4068 entries[0].pidl = NULL;
4070 hr = SHILCreateFromPath(root_dirW, (LPITEMIDLIST*)&entries[0].pidl, 0);
4072 hr = SHILCreateFromPath((LPCVOID)root_dirA, (LPITEMIDLIST*)&entries[0].pidl, 0);
4073 ok(hr == S_OK, "SHILCreateFromPath failed: 0x%08x\n", hr);
4074 entries[0].fRecursive = TRUE;
4076 notifyID = SHChangeNotifyRegister(wnd, SHCNRF_ShellLevel,
4077 SHCNE_ALLEVENTS, WM_USER_NOTIFY, 1, entries);
4078 ok(notifyID != 0, "Failed to register a window for change notifications\n");
4081 br = CreateDirectoryA(test_dirA, NULL);
4082 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
4085 exp_data.id = "MKDIR PATHW";
4086 exp_data.signal = SHCNE_MKDIR;
4087 exp_data.exp_notify = TRUE;
4088 exp_data.path_1 = test_dirW;
4089 exp_data.path_2 = NULL;
4090 SHChangeNotify(SHCNE_MKDIR, SHCNF_PATHW | SHCNF_FLUSH, test_dirW, NULL);
4092 ok(exp_data.exp_notify == FALSE, "Expected wndproc to be called\n");
4094 win_skip("skipping WCHAR tests\n");
4096 exp_data.id = "MKDIR PATHA";
4097 exp_data.signal = SHCNE_MKDIR;
4098 exp_data.exp_notify = TRUE;
4099 exp_data.path_1 = test_dirW;
4100 exp_data.path_2 = NULL;
4101 SHChangeNotify(SHCNE_MKDIR, SHCNF_PATHA | SHCNF_FLUSH, test_dirA, NULL);
4103 ok(exp_data.exp_notify == FALSE, "Expected wndproc to be called\n");
4106 br = RemoveDirectoryA(test_dirA);
4107 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4110 exp_data.id = "RMDIR PATHW";
4111 exp_data.signal = SHCNE_RMDIR;
4112 exp_data.exp_notify = TRUE;
4113 exp_data.path_1 = test_dirW;
4114 exp_data.path_2 = NULL;
4115 SHChangeNotify(SHCNE_RMDIR, SHCNF_PATHW | SHCNF_FLUSH, test_dirW, NULL);
4117 ok(exp_data.exp_notify == FALSE, "Expected wndproc to be called\n");
4119 win_skip("skipping WCHAR tests\n");
4121 exp_data.id = "RMDIR PATHA";
4122 exp_data.signal = SHCNE_RMDIR;
4123 exp_data.exp_notify = TRUE;
4124 exp_data.path_1 = test_dirW;
4125 exp_data.path_2 = NULL;
4126 SHChangeNotify(SHCNE_RMDIR, SHCNF_PATHA | SHCNF_FLUSH, test_dirA, NULL);
4128 ok(exp_data.exp_notify == FALSE, "Expected wndproc to be called\n");
4130 SHChangeNotifyDeregister(notifyID);
4133 br = RemoveDirectoryA(root_dirA);
4134 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4137 START_TEST(shlfolder)
4139 init_function_pointers();
4140 /* if OleInitialize doesn't get called, ParseDisplayName returns
4141 CO_E_NOTINITIALIZED for malformed directory names on win2k. */
4142 OleInitialize(NULL);
4144 test_ParseDisplayName();
4145 test_SHParseDisplayName();
4146 test_BindToObject();
4147 test_EnumObjects_and_CompareIDs();
4148 test_GetDisplayName();
4149 test_GetAttributesOf();
4150 test_SHGetPathFromIDList();
4151 test_CallForAttributes();
4152 test_FolderShortcut();
4153 test_ITEMIDLIST_format();
4154 test_SHGetFolderPathA();
4155 test_SHGetFolderPathAndSubDirA();
4156 test_LocalizedNames();
4157 test_SHCreateShellItem();
4158 test_SHCreateShellItemArray();
4159 test_desktop_IPersist();
4161 test_SHSimpleIDListFromPath();
4162 test_ParseDisplayNamePBC();
4163 test_SHGetNameFromIDList();
4164 test_SHGetItemFromDataObject();
4165 test_SHGetIDListFromObject();
4166 test_SHGetItemFromObject();
4167 test_ShellItemCompare();
4168 test_SHChangeNotify();
4169 test_ShellItemBindToHandler();