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);
44 DEFINE_GUID(CLSID_ShellDocObjView, 0xe7e4bc40, 0xe76a, 0x11ce, 0xa9,0xbb, 0x00,0xaa,0x00,0x4a,0xe8,0x37);
48 static HRESULT (WINAPI *pSHBindToParent)(LPCITEMIDLIST, REFIID, LPVOID*, LPCITEMIDLIST*);
49 static HRESULT (WINAPI *pSHGetFolderPathA)(HWND, int, HANDLE, DWORD, LPSTR);
50 static HRESULT (WINAPI *pSHGetFolderPathAndSubDirA)(HWND, int, HANDLE, DWORD, LPCSTR, LPSTR);
51 static BOOL (WINAPI *pSHGetPathFromIDListW)(LPCITEMIDLIST,LPWSTR);
52 static HRESULT (WINAPI *pSHGetSpecialFolderLocation)(HWND, int, LPITEMIDLIST *);
53 static BOOL (WINAPI *pSHGetSpecialFolderPathA)(HWND, LPSTR, int, BOOL);
54 static BOOL (WINAPI *pSHGetSpecialFolderPathW)(HWND, LPWSTR, int, BOOL);
55 static HRESULT (WINAPI *pStrRetToBufW)(STRRET*,LPCITEMIDLIST,LPWSTR,UINT);
56 static LPITEMIDLIST (WINAPI *pILFindLastID)(LPCITEMIDLIST);
57 static void (WINAPI *pILFree)(LPITEMIDLIST);
58 static BOOL (WINAPI *pILIsEqual)(LPCITEMIDLIST, LPCITEMIDLIST);
59 static HRESULT (WINAPI *pSHCreateItemFromIDList)(PCIDLIST_ABSOLUTE pidl, REFIID riid, void **ppv);
60 static HRESULT (WINAPI *pSHCreateItemFromParsingName)(PCWSTR,IBindCtx*,REFIID,void**);
61 static HRESULT (WINAPI *pSHCreateShellItem)(LPCITEMIDLIST,IShellFolder*,LPCITEMIDLIST,IShellItem**);
62 static HRESULT (WINAPI *pSHCreateShellItemArray)(LPCITEMIDLIST,IShellFolder*,UINT,LPCITEMIDLIST*,IShellItemArray**);
63 static HRESULT (WINAPI *pSHCreateShellItemArrayFromDataObject)(IDataObject*, REFIID, void **);
64 static HRESULT (WINAPI *pSHCreateShellItemArrayFromShellItem)(IShellItem*, REFIID, void **);
65 static LPITEMIDLIST (WINAPI *pILCombine)(LPCITEMIDLIST,LPCITEMIDLIST);
66 static HRESULT (WINAPI *pSHParseDisplayName)(LPCWSTR,IBindCtx*,LPITEMIDLIST*,SFGAOF,SFGAOF*);
67 static LPITEMIDLIST (WINAPI *pSHSimpleIDListFromPathAW)(LPCVOID);
68 static HRESULT (WINAPI *pSHGetNameFromIDList)(PCIDLIST_ABSOLUTE,SIGDN,PWSTR*);
69 static HRESULT (WINAPI *pSHGetItemFromDataObject)(IDataObject*,DATAOBJ_GET_ITEM_FLAGS,REFIID,void**);
70 static HRESULT (WINAPI *pSHGetIDListFromObject)(IUnknown*, PIDLIST_ABSOLUTE*);
71 static HRESULT (WINAPI *pSHGetItemFromObject)(IUnknown*,REFIID,void**);
72 static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
74 static WCHAR *make_wstr(const char *str)
79 if(!str || strlen(str) == 0)
82 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
86 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
90 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
94 static int strcmp_wa(LPCWSTR strw, const char *stra)
97 WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL);
98 return lstrcmpA(stra, buf);
101 static void init_function_pointers(void)
107 hmod = GetModuleHandleA("shell32.dll");
109 #define MAKEFUNC(f) (p##f = (void*)GetProcAddress(hmod, #f))
110 MAKEFUNC(SHBindToParent);
111 MAKEFUNC(SHCreateItemFromIDList);
112 MAKEFUNC(SHCreateItemFromParsingName);
113 MAKEFUNC(SHCreateShellItem);
114 MAKEFUNC(SHCreateShellItemArray);
115 MAKEFUNC(SHCreateShellItemArrayFromDataObject);
116 MAKEFUNC(SHCreateShellItemArrayFromShellItem);
117 MAKEFUNC(SHGetFolderPathA);
118 MAKEFUNC(SHGetFolderPathAndSubDirA);
119 MAKEFUNC(SHGetPathFromIDListW);
120 MAKEFUNC(SHGetSpecialFolderPathA);
121 MAKEFUNC(SHGetSpecialFolderPathW);
122 MAKEFUNC(SHGetSpecialFolderLocation);
123 MAKEFUNC(SHParseDisplayName);
124 MAKEFUNC(SHGetNameFromIDList);
125 MAKEFUNC(SHGetItemFromDataObject);
126 MAKEFUNC(SHGetIDListFromObject);
127 MAKEFUNC(SHGetItemFromObject);
130 #define MAKEFUNC_ORD(f, ord) (p##f = (void*)GetProcAddress(hmod, (LPSTR)(ord)))
131 MAKEFUNC_ORD(ILFindLastID, 16);
132 MAKEFUNC_ORD(ILIsEqual, 21);
133 MAKEFUNC_ORD(ILCombine, 25);
134 MAKEFUNC_ORD(ILFree, 155);
135 MAKEFUNC_ORD(SHSimpleIDListFromPathAW, 162);
138 /* test named exports */
139 ptr = GetProcAddress(hmod, "ILFree");
140 ok(broken(ptr == 0) || ptr != 0, "expected named export for ILFree\n");
143 #define TESTNAMED(f) \
144 ptr = (void*)GetProcAddress(hmod, #f); \
145 ok(ptr != 0, "expected named export for " #f "\n");
147 TESTNAMED(ILAppendID);
149 TESTNAMED(ILCloneFirst);
150 TESTNAMED(ILCombine);
151 TESTNAMED(ILCreateFromPath);
152 TESTNAMED(ILCreateFromPathA);
153 TESTNAMED(ILCreateFromPathW);
154 TESTNAMED(ILFindChild);
155 TESTNAMED(ILFindLastID);
156 TESTNAMED(ILGetNext);
157 TESTNAMED(ILGetSize);
158 TESTNAMED(ILIsEqual);
159 TESTNAMED(ILIsParent);
160 TESTNAMED(ILRemoveLastID);
161 TESTNAMED(ILSaveToStream);
165 hmod = GetModuleHandleA("shlwapi.dll");
166 pStrRetToBufW = (void*)GetProcAddress(hmod, "StrRetToBufW");
168 pIsWow64Process = (void*)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process");
170 hr = SHGetMalloc(&ppM);
171 ok(hr == S_OK, "SHGetMalloc failed %08x\n", hr);
174 /* Based on PathAddBackslashW from dlls/shlwapi/path.c */
175 static LPWSTR myPathAddBackslashW( LPWSTR lpszPath )
179 if (!lpszPath || (iLen = lstrlenW(lpszPath)) >= MAX_PATH)
185 if (lpszPath[-1] != '\\')
194 static void test_ParseDisplayName(void)
197 IShellFolder *IDesktopFolder;
198 static const char *cNonExistDir1A = "c:\\nonexist_subdir";
199 static const char *cNonExistDir2A = "c:\\\\nonexist_subdir";
200 static const char *cInetTestA = "http:\\yyy";
201 static const char *cInetTest2A = "xx:yyy";
203 WCHAR cTestDirW [MAX_PATH] = {0};
207 hr = SHGetDesktopFolder(&IDesktopFolder);
208 ok(hr == S_OK, "Expected SHGetDesktopFolder to return S_OK, got 0x%08x\n", hr);
209 if(hr != S_OK) return;
211 /* Tests crash on W2K and below (SHCreateShellItem available as of XP) */
212 if (pSHCreateShellItem)
214 /* null name and pidl */
215 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
216 NULL, NULL, NULL, NULL, NULL, 0);
217 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
220 newPIDL = (ITEMIDLIST*)0xdeadbeef;
221 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
222 NULL, NULL, NULL, NULL, &newPIDL, 0);
223 ok(newPIDL == 0, "expected null, got %p\n", newPIDL);
224 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
227 win_skip("Tests would crash on W2K and below\n");
229 MultiByteToWideChar(CP_ACP, 0, cInetTestA, -1, cTestDirW, MAX_PATH);
230 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
231 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
232 todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
233 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
236 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
237 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
238 IMalloc_Free(ppM, newPIDL);
241 MultiByteToWideChar(CP_ACP, 0, cInetTest2A, -1, cTestDirW, MAX_PATH);
242 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
243 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
244 todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
245 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
248 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
249 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
250 IMalloc_Free(ppM, newPIDL);
253 res = GetFileAttributesA(cNonExistDir1A);
254 if(res != INVALID_FILE_ATTRIBUTES)
256 skip("Test directory unexpectedly exists\n");
260 MultiByteToWideChar(CP_ACP, 0, cNonExistDir1A, -1, cTestDirW, MAX_PATH);
261 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
262 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
263 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL),
264 "ParseDisplayName returned %08x, expected 80070002 or E_FAIL\n", hr);
266 res = GetFileAttributesA(cNonExistDir2A);
267 if(res != INVALID_FILE_ATTRIBUTES)
269 skip("Test directory unexpectedly exists\n");
273 MultiByteToWideChar(CP_ACP, 0, cNonExistDir2A, -1, cTestDirW, MAX_PATH);
274 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
275 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
276 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL) || (hr == E_INVALIDARG),
277 "ParseDisplayName returned %08x, expected 80070002, E_FAIL or E_INVALIDARG\n", hr);
279 /* I thought that perhaps the DesktopFolder's ParseDisplayName would recognize the
280 * path corresponding to CSIDL_PERSONAL and return a CLSID_MyDocuments PIDL. Turns
281 * out it doesn't. The magic seems to happen in the file dialogs, then. */
282 if (!pSHGetSpecialFolderPathW || !pILFindLastID)
284 win_skip("SHGetSpecialFolderPathW and/or ILFindLastID are not available\n");
288 bRes = pSHGetSpecialFolderPathW(NULL, cTestDirW, CSIDL_PERSONAL, FALSE);
289 ok(bRes, "SHGetSpecialFolderPath(CSIDL_PERSONAL) failed! %u\n", GetLastError());
290 if (!bRes) goto finished;
292 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
293 ok(hr == S_OK, "DesktopFolder->ParseDisplayName failed. hr = %08x.\n", hr);
294 if (hr != S_OK) goto finished;
296 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x31 ||
297 pILFindLastID(newPIDL)->mkid.abID[0] == 0xb1, /* Win98 */
298 "Last pidl should be of type PT_FOLDER or PT_IESPECIAL2, but is: %02x\n",
299 pILFindLastID(newPIDL)->mkid.abID[0]);
300 IMalloc_Free(ppM, newPIDL);
303 IShellFolder_Release(IDesktopFolder);
306 /* creates a file with the specified name for tests */
307 static void CreateTestFile(const CHAR *name)
312 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
313 if (file != INVALID_HANDLE_VALUE)
315 WriteFile(file, name, strlen(name), &written, NULL);
316 WriteFile(file, "\n", strlen("\n"), &written, NULL);
322 /* initializes the tests */
323 static void CreateFilesFolders(void)
325 CreateDirectoryA(".\\testdir", NULL);
326 CreateDirectoryA(".\\testdir\\test.txt", NULL);
327 CreateTestFile (".\\testdir\\test1.txt ");
328 CreateTestFile (".\\testdir\\test2.txt ");
329 CreateTestFile (".\\testdir\\test3.txt ");
330 CreateDirectoryA(".\\testdir\\testdir2 ", NULL);
331 CreateDirectoryA(".\\testdir\\testdir2\\subdir", NULL);
334 /* cleans after tests */
335 static void Cleanup(void)
337 DeleteFileA(".\\testdir\\test1.txt");
338 DeleteFileA(".\\testdir\\test2.txt");
339 DeleteFileA(".\\testdir\\test3.txt");
340 RemoveDirectoryA(".\\testdir\\test.txt");
341 RemoveDirectoryA(".\\testdir\\testdir2\\subdir");
342 RemoveDirectoryA(".\\testdir\\testdir2");
343 RemoveDirectoryA(".\\testdir");
348 static void test_EnumObjects(IShellFolder *iFolder)
350 IEnumIDList *iEnumList;
351 LPITEMIDLIST newPIDL, idlArr[10];
356 static const WORD iResults [5][5] =
365 #define SFGAO_testfor SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | SFGAO_CAPABILITYMASK
366 /* Don't test for SFGAO_HASSUBFOLDER since we return real state and native cached */
367 static const ULONG attrs[5] =
369 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
370 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
371 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
372 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
373 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
376 hr = IShellFolder_EnumObjects(iFolder, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &iEnumList);
377 ok(hr == S_OK, "EnumObjects failed %08x\n", hr);
379 /* This is to show that, contrary to what is said on MSDN, on IEnumIDList::Next,
380 * the filesystem shellfolders return S_OK even if less than 'celt' items are
381 * returned (in contrast to S_FALSE). We have to do it in a loop since WinXP
382 * only ever returns a single entry per call. */
383 while (IEnumIDList_Next(iEnumList, 10-i, &idlArr[i], &NumPIDLs) == S_OK)
385 ok (i == 5, "i: %d\n", i);
387 hr = IEnumIDList_Release(iEnumList);
388 ok(hr == S_OK, "IEnumIDList_Release failed %08x\n", hr);
390 /* Sort them first in case of wrong order from system */
391 for (i=0;i<5;i++) for (j=0;j<5;j++)
392 if ((SHORT)IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]) < 0)
395 idlArr[i] = idlArr[j];
399 for (i=0;i<5;i++) for (j=0;j<5;j++)
401 hr = IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]);
402 ok(hr == iResults[i][j], "Got %x expected [%d]-[%d]=%x\n", hr, i, j, iResults[i][j]);
406 for (i = 0; i < 5; i++)
409 #define SFGAO_VISTA SFGAO_DROPTARGET | SFGAO_CANLINK | SFGAO_CANCOPY
410 /* Native returns all flags no matter what we ask for */
411 flags = SFGAO_CANCOPY;
412 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
413 flags &= SFGAO_testfor;
414 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
415 ok(flags == (attrs[i]) ||
416 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR) || /* Win9x, NT4 */
417 flags == ((attrs[i] & ~SFGAO_CAPABILITYMASK) | SFGAO_VISTA), /* Vista and higher */
418 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
420 flags = SFGAO_testfor;
421 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
422 flags &= SFGAO_testfor;
423 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
424 ok(flags == attrs[i] ||
425 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR), /* Win9x, NT4 */
426 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
430 IMalloc_Free(ppM, idlArr[i]);
433 static void test_BindToObject(void)
437 IShellFolder *psfDesktop, *psfChild, *psfMyComputer, *psfSystemDir;
438 SHITEMID emptyitem = { 0, { 0 } };
439 LPITEMIDLIST pidlMyComputer, pidlSystemDir, pidl, pidlEmpty = (LPITEMIDLIST)&emptyitem;
440 WCHAR wszSystemDir[MAX_PATH];
441 char szSystemDir[MAX_PATH];
443 WCHAR path[MAX_PATH];
444 CHAR pathA[MAX_PATH];
446 WCHAR wszMyComputer[] = {
447 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
448 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
449 static const CHAR filename_html[] = "winetest.html";
450 static const CHAR filename_txt[] = "winetest.txt";
451 static const CHAR filename_foo[] = "winetest.foo";
453 /* The following tests shows that BindToObject should fail with E_INVALIDARG if called
454 * with an empty pidl. This is tested for Desktop, MyComputer and the FS ShellFolder
456 hr = SHGetDesktopFolder(&psfDesktop);
457 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
458 if (hr != S_OK) return;
460 hr = IShellFolder_BindToObject(psfDesktop, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
461 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
463 hr = IShellFolder_BindToObject(psfDesktop, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
464 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
466 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
467 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
469 IShellFolder_Release(psfDesktop);
473 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
474 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
475 IShellFolder_Release(psfDesktop);
476 IMalloc_Free(ppM, pidlMyComputer);
477 if (hr != S_OK) return;
479 hr = IShellFolder_BindToObject(psfMyComputer, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
480 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
484 /* this call segfaults on 98SE */
485 hr = IShellFolder_BindToObject(psfMyComputer, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
486 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
489 cChars = GetSystemDirectoryA(szSystemDir, MAX_PATH);
490 ok (cChars > 0 && cChars < MAX_PATH, "GetSystemDirectoryA failed! LastError: %u\n", GetLastError());
491 if (cChars == 0 || cChars >= MAX_PATH) {
492 IShellFolder_Release(psfMyComputer);
495 MultiByteToWideChar(CP_ACP, 0, szSystemDir, -1, wszSystemDir, MAX_PATH);
497 hr = IShellFolder_ParseDisplayName(psfMyComputer, NULL, NULL, wszSystemDir, NULL, &pidlSystemDir, NULL);
498 ok (hr == S_OK, "MyComputers's ParseDisplayName failed to parse the SystemDirectory! hr = %08x\n", hr);
500 IShellFolder_Release(psfMyComputer);
504 hr = IShellFolder_BindToObject(psfMyComputer, pidlSystemDir, NULL, &IID_IShellFolder, (LPVOID*)&psfSystemDir);
505 ok (hr == S_OK, "MyComputer failed to bind to a FileSystem ShellFolder! hr = %08x\n", hr);
506 IShellFolder_Release(psfMyComputer);
507 IMalloc_Free(ppM, pidlSystemDir);
508 if (hr != S_OK) return;
510 hr = IShellFolder_BindToObject(psfSystemDir, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
511 ok (hr == E_INVALIDARG,
512 "FileSystem ShellFolder's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
516 /* this call segfaults on 98SE */
517 hr = IShellFolder_BindToObject(psfSystemDir, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
518 ok (hr == E_INVALIDARG,
519 "FileSystem ShellFolder's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
522 IShellFolder_Release(psfSystemDir);
524 GetCurrentDirectoryA(MAX_PATH, buf);
527 skip("Failed to get current directory, skipping tests.\n");
531 SHGetDesktopFolder(&psfDesktop);
533 /* Attempt BindToObject on files. */
536 lstrcpyA(pathA, buf);
537 lstrcatA(pathA, "\\");
538 lstrcatA(pathA, filename_html);
539 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
540 if(hfile != INVALID_HANDLE_VALUE)
543 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
544 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
545 ok(hr == S_OK, "Got 0x%08x\n", hr);
548 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
550 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
555 hr = IShellFolder_QueryInterface(psfChild, &IID_IPersist, (void**)&pp);
557 broken(hr == E_NOINTERFACE), /* Win9x, NT4, W2K */
562 hr = IPersist_GetClassID(pp, &id);
563 ok(hr == S_OK, "Got 0x%08x\n", hr);
564 ok(IsEqualIID(&id, &CLSID_ShellDocObjView), "Unexpected classid\n");
565 IPersist_Release(pp);
568 IShellFolder_Release(psfChild);
575 win_skip("Failed to create .html testfile.\n");
578 lstrcpyA(pathA, buf);
579 lstrcatA(pathA, "\\");
580 lstrcatA(pathA, filename_txt);
581 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
582 if(hfile != INVALID_HANDLE_VALUE)
585 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
586 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
587 ok(hr == S_OK, "Got 0x%08x\n", hr);
590 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
591 ok(hr == E_FAIL || /* Vista+ */
592 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || /* XP, W2K3 */
593 broken(hr == S_OK), /* Win9x, NT4, W2K */
595 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
601 win_skip("Failed to create .txt testfile.\n");
604 lstrcpyA(pathA, buf);
605 lstrcatA(pathA, "\\");
606 lstrcatA(pathA, filename_foo);
607 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
608 if(hfile != INVALID_HANDLE_VALUE)
611 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
612 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
613 ok(hr == S_OK, "Got 0x%08x\n", hr);
616 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
617 ok(hr == E_FAIL || /* Vista+ */
618 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || /* XP, W2K3 */
619 broken(hr == S_OK), /* Win9x, NT4, W2K */
621 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
627 win_skip("Failed to create .foo testfile.\n");
629 /* And on the desktop */
630 if(pSHGetSpecialFolderPathA)
632 pSHGetSpecialFolderPathA(NULL, pathA, CSIDL_DESKTOP, FALSE);
633 lstrcatA(pathA, "\\");
634 lstrcatA(pathA, filename_html);
635 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
636 if(hfile != INVALID_HANDLE_VALUE)
639 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
640 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
641 ok(hr == S_OK, "Got 0x%08x\n", hr);
644 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
646 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
648 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
651 if(!DeleteFileA(pathA))
652 trace("Failed to delete: %d\n", GetLastError());
656 win_skip("Failed to create .html testfile.\n");
658 pSHGetSpecialFolderPathA(NULL, pathA, CSIDL_DESKTOP, FALSE);
659 lstrcatA(pathA, "\\");
660 lstrcatA(pathA, filename_foo);
661 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
662 if(hfile != INVALID_HANDLE_VALUE)
665 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
666 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
667 ok(hr == S_OK, "Got 0x%08x\n", hr);
670 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
671 ok(hr == E_FAIL || /* Vista+ */
672 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || /* XP, W2K3 */
673 broken(hr == S_OK), /* Win9x, NT4, W2K */
675 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
681 win_skip("Failed to create .foo testfile.\n");
684 IShellFolder_Release(psfDesktop);
687 static void test_GetDisplayName(void)
692 WCHAR wszTestFile[MAX_PATH], wszTestFile2[MAX_PATH];
693 char szTestFile[MAX_PATH], szTestDir[MAX_PATH];
696 LPSHELLFOLDER psfDesktop, psfPersonal;
698 SHITEMID emptyitem = { 0, { 0 } };
699 LPITEMIDLIST pidlTestFile, pidlEmpty = (LPITEMIDLIST)&emptyitem;
700 LPCITEMIDLIST pidlLast;
701 static const CHAR szFileName[] = "winetest.foo";
702 static const WCHAR wszFileName[] = { 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
703 static const WCHAR wszDirName[] = { 'w','i','n','e','t','e','s','t',0 };
705 /* I'm trying to figure if there is a functional difference between calling
706 * SHGetPathFromIDListW and calling GetDisplayNameOf(SHGDN_FORPARSING) after
707 * binding to the shellfolder. One thing I thought of was that perhaps
708 * SHGetPathFromIDListW would be able to get the path to a file, which does
709 * not exist anymore, while the other method wouldn't. It turns out there's
710 * no functional difference in this respect.
713 if(!pSHGetSpecialFolderPathA) {
714 win_skip("SHGetSpecialFolderPathA is not available\n");
718 /* First creating a directory in MyDocuments and a file in this directory. */
719 result = pSHGetSpecialFolderPathA(NULL, szTestDir, CSIDL_PERSONAL, FALSE);
720 ok(result, "SHGetSpecialFolderPathA failed! Last error: %u\n", GetLastError());
723 /* Use ANSI file functions so this works on Windows 9x */
724 lstrcatA(szTestDir, "\\winetest");
725 CreateDirectoryA(szTestDir, NULL);
726 attr=GetFileAttributesA(szTestDir);
727 if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY))
729 ok(0, "unable to create the '%s' directory\n", szTestDir);
733 lstrcpyA(szTestFile, szTestDir);
734 lstrcatA(szTestFile, "\\");
735 lstrcatA(szTestFile, szFileName);
736 hTestFile = CreateFileA(szTestFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
737 ok((hTestFile != INVALID_HANDLE_VALUE), "CreateFileA failed! Last error: %u\n", GetLastError());
738 if (hTestFile == INVALID_HANDLE_VALUE) return;
739 CloseHandle(hTestFile);
741 /* Getting an itemidlist for the file. */
742 hr = SHGetDesktopFolder(&psfDesktop);
743 ok(hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
744 if (hr != S_OK) return;
746 MultiByteToWideChar(CP_ACP, 0, szTestFile, -1, wszTestFile, MAX_PATH);
748 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
749 ok(hr == S_OK, "Desktop->ParseDisplayName failed! hr = %08x\n", hr);
751 IShellFolder_Release(psfDesktop);
755 pidlLast = pILFindLastID(pidlTestFile);
756 ok(pidlLast->mkid.cb >=76 ||
757 broken(pidlLast->mkid.cb == 28) || /* W2K */
758 broken(pidlLast->mkid.cb == 40), /* Win9x, WinME */
759 "Expected pidl length of at least 76, got %d.\n", pidlLast->mkid.cb);
760 if (pidlLast->mkid.cb >= 28) {
761 ok(!lstrcmpA((CHAR*)&pidlLast->mkid.abID[12], szFileName),
762 "Filename should be stored as ansi-string at this position!\n");
764 /* WinXP and up store the filenames as both ANSI and UNICODE in the pidls */
765 if (pidlLast->mkid.cb >= 76) {
766 ok(!lstrcmpW((WCHAR*)&pidlLast->mkid.abID[46], wszFileName) ||
767 (pidlLast->mkid.cb >= 94 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[64], wszFileName)) || /* Vista */
768 (pidlLast->mkid.cb >= 98 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[68], wszFileName)), /* Win7 */
769 "Filename should be stored as wchar-string at this position!\n");
772 /* It seems as if we cannot bind to regular files on windows, but only directories.
774 hr = IShellFolder_BindToObject(psfDesktop, pidlTestFile, NULL, &IID_IUnknown, (VOID**)&psfFile);
775 ok (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
776 hr == E_NOTIMPL || /* Vista */
777 broken(hr == S_OK), /* Win9x, W2K */
780 IShellFolder_Release(psfFile);
783 if (!pSHBindToParent)
785 win_skip("SHBindToParent is missing\n");
786 DeleteFileA(szTestFile);
787 RemoveDirectoryA(szTestDir);
791 /* Some tests for IShellFolder::SetNameOf */
792 if (pSHGetFolderPathAndSubDirA)
794 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
795 ok(hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
797 /* It's ok to use this fixed path. Call will fail anyway. */
798 WCHAR wszAbsoluteFilename[] = { 'C',':','\\','w','i','n','e','t','e','s','t', 0 };
799 LPITEMIDLIST pidlNew;
801 /* The pidl returned through the last parameter of SetNameOf is a simple one. */
802 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlLast, wszDirName, SHGDN_NORMAL, &pidlNew);
803 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
806 ok (((LPITEMIDLIST)((LPBYTE)pidlNew+pidlNew->mkid.cb))->mkid.cb == 0,
807 "pidl returned from SetNameOf should be simple!\n");
809 /* Passing an absolute path to SetNameOf fails. The HRESULT code indicates that SetNameOf
810 * is implemented on top of SHFileOperation in WinXP. */
811 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszAbsoluteFilename,
812 SHGDN_FORPARSING, NULL);
813 ok (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED), "SetNameOf succeeded! hr = %08x\n", hr);
815 /* Rename the file back to its original name. SetNameOf ignores the fact, that the
816 * SHGDN flags specify an absolute path. */
817 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszFileName, SHGDN_FORPARSING, NULL);
818 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
823 IShellFolder_Release(psfPersonal);
827 win_skip("Avoid needs of interaction on Win2k\n");
829 /* Deleting the file and the directory */
830 DeleteFileA(szTestFile);
831 RemoveDirectoryA(szTestDir);
833 /* SHGetPathFromIDListW still works, although the file is not present anymore. */
834 if (pSHGetPathFromIDListW)
836 result = pSHGetPathFromIDListW(pidlTestFile, wszTestFile2);
837 ok (result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
838 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "SHGetPathFromIDListW returns incorrect path!\n");
841 /* SHBindToParent fails, if called with a NULL PIDL. */
842 hr = pSHBindToParent(NULL, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
843 ok (hr != S_OK, "SHBindToParent(NULL) should fail!\n");
845 /* But it succeeds with an empty PIDL. */
846 hr = pSHBindToParent(pidlEmpty, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
847 ok (hr == S_OK, "SHBindToParent(empty PIDL) should succeed! hr = %08x\n", hr);
848 ok (pidlLast == pidlEmpty, "The last element of an empty PIDL should be the PIDL itself!\n");
850 IShellFolder_Release(psfPersonal);
852 /* Binding to the folder and querying the display name of the file also works. */
853 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
854 ok (hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
856 IShellFolder_Release(psfDesktop);
860 /* This test shows that Windows doesn't allocate a new pidlLast, but returns a pointer into
861 * pidlTestFile (In accordance with MSDN). */
862 ok (pILFindLastID(pidlTestFile) == pidlLast,
863 "SHBindToParent doesn't return the last id of the pidl param!\n");
865 hr = IShellFolder_GetDisplayNameOf(psfPersonal, pidlLast, SHGDN_FORPARSING, &strret);
866 ok (hr == S_OK, "Personal->GetDisplayNameOf failed! hr = %08x\n", hr);
868 IShellFolder_Release(psfDesktop);
869 IShellFolder_Release(psfPersonal);
875 hr = pStrRetToBufW(&strret, pidlLast, wszTestFile2, MAX_PATH);
876 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
877 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "GetDisplayNameOf returns incorrect path!\n");
880 ILFree(pidlTestFile);
881 IShellFolder_Release(psfDesktop);
882 IShellFolder_Release(psfPersonal);
885 static void test_CallForAttributes(void)
891 LPSHELLFOLDER psfDesktop;
892 LPITEMIDLIST pidlMyDocuments;
893 DWORD dwAttributes, dwCallForAttributes, dwOrigAttributes, dwOrigCallForAttributes;
894 static const WCHAR wszAttributes[] = { 'A','t','t','r','i','b','u','t','e','s',0 };
895 static const WCHAR wszCallForAttributes[] = {
896 'C','a','l','l','F','o','r','A','t','t','r','i','b','u','t','e','s',0 };
897 static const WCHAR wszMyDocumentsKey[] = {
898 'C','L','S','I','D','\\','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-',
899 '1','1','D','0','-','9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',
900 '\\','S','h','e','l','l','F','o','l','d','e','r',0 };
901 WCHAR wszMyDocuments[] = {
902 ':',':','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-','1','1','D','0','-',
903 '9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',0 };
905 /* For the root of a namespace extension, the attributes are not queried by binding
906 * to the object and calling GetAttributesOf. Instead, the attributes are read from
907 * the registry value HKCR/CLSID/{...}/ShellFolder/Attributes. This is documented on MSDN.
909 * The MyDocuments shellfolder on WinXP has a HKCR/CLSID/{...}/ShellFolder/CallForAttributes
910 * value. It seems that if the folder is queried for one of the flags set in CallForAttributes,
911 * the shell does bind to the folder object and calls GetAttributesOf. This is not documented
912 * on MSDN. This test is meant to document the observed behaviour on WinXP SP2.
914 hr = SHGetDesktopFolder(&psfDesktop);
915 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
916 if (hr != S_OK) return;
918 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyDocuments, NULL,
919 &pidlMyDocuments, NULL);
921 broken(hr == E_INVALIDARG), /* Win95, NT4 */
922 "Desktop's ParseDisplayName failed to parse MyDocuments's CLSID! hr = %08x\n", hr);
924 IShellFolder_Release(psfDesktop);
928 dwAttributes = 0xffffffff;
929 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
930 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
931 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
933 /* We need the following setup (as observed on WinXP SP2), for the tests to make sense. */
934 ok (dwAttributes & SFGAO_FILESYSTEM, "SFGAO_FILESYSTEM attribute is not set for MyDocuments!\n");
935 ok (!(dwAttributes & SFGAO_ISSLOW), "SFGAO_ISSLOW attribute is set for MyDocuments!\n");
936 ok (!(dwAttributes & SFGAO_GHOSTED), "SFGAO_GHOSTED attribute is set for MyDocuments!\n");
938 /* We don't have the MyDocuments shellfolder in wine yet, and thus we don't have the registry
939 * key. So the test will return at this point, if run on wine.
941 lResult = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszMyDocumentsKey, 0, KEY_WRITE|KEY_READ, &hKey);
942 ok (lResult == ERROR_SUCCESS ||
943 lResult == ERROR_ACCESS_DENIED,
944 "RegOpenKeyEx failed! result: %08x\n", lResult);
945 if (lResult != ERROR_SUCCESS) {
946 if (lResult == ERROR_ACCESS_DENIED)
947 skip("Not enough rights to open the registry key\n");
948 IMalloc_Free(ppM, pidlMyDocuments);
949 IShellFolder_Release(psfDesktop);
953 /* Query MyDocuments' Attributes value, to be able to restore it later. */
954 dwSize = sizeof(DWORD);
955 lResult = RegQueryValueExW(hKey, wszAttributes, NULL, NULL, (LPBYTE)&dwOrigAttributes, &dwSize);
956 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
957 if (lResult != ERROR_SUCCESS) {
959 IMalloc_Free(ppM, pidlMyDocuments);
960 IShellFolder_Release(psfDesktop);
964 /* Query MyDocuments' CallForAttributes value, to be able to restore it later. */
965 dwSize = sizeof(DWORD);
966 lResult = RegQueryValueExW(hKey, wszCallForAttributes, NULL, NULL,
967 (LPBYTE)&dwOrigCallForAttributes, &dwSize);
968 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
969 if (lResult != ERROR_SUCCESS) {
971 IMalloc_Free(ppM, pidlMyDocuments);
972 IShellFolder_Release(psfDesktop);
976 /* Define via the Attributes value that MyDocuments attributes are SFGAO_ISSLOW and
977 * SFGAO_GHOSTED and that MyDocuments should be called for the SFGAO_ISSLOW and
978 * SFGAO_FILESYSTEM attributes. */
979 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED;
980 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwAttributes, sizeof(DWORD));
981 dwCallForAttributes = SFGAO_ISSLOW|SFGAO_FILESYSTEM;
982 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
983 (LPBYTE)&dwCallForAttributes, sizeof(DWORD));
985 /* Although it is not set in CallForAttributes, the SFGAO_GHOSTED flag is reset by
986 * GetAttributesOf. It seems that once there is a single attribute queried, for which
987 * CallForAttributes is set, all flags are taken from the GetAttributesOf call and
988 * the flags in Attributes are ignored.
990 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED|SFGAO_FILESYSTEM;
991 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
992 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
993 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
995 ok (dwAttributes == SFGAO_FILESYSTEM,
996 "Desktop->GetAttributes(MyDocuments) returned unexpected attributes: %08x\n",
999 /* Restore MyDocuments' original Attributes and CallForAttributes registry values */
1000 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwOrigAttributes, sizeof(DWORD));
1001 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
1002 (LPBYTE)&dwOrigCallForAttributes, sizeof(DWORD));
1004 IMalloc_Free(ppM, pidlMyDocuments);
1005 IShellFolder_Release(psfDesktop);
1008 static void test_GetAttributesOf(void)
1011 LPSHELLFOLDER psfDesktop, psfMyComputer;
1012 SHITEMID emptyitem = { 0, { 0 } };
1013 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
1014 LPITEMIDLIST pidlMyComputer;
1016 static const DWORD desktopFlags[] = {
1018 SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSANCESTOR |
1019 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
1021 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_STREAM | SFGAO_FILESYSANCESTOR |
1022 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
1023 /* WinMe, Win9x, WinNT*/
1024 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSANCESTOR |
1025 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
1027 static const DWORD myComputerFlags[] = {
1029 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
1030 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1032 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_STREAM |
1033 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1034 /* WinMe, Win9x, WinNT */
1035 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
1036 SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1037 /* Win95, WinNT when queried directly */
1038 SFGAO_CANLINK | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
1039 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
1041 WCHAR wszMyComputer[] = {
1042 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
1043 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
1044 char cCurrDirA [MAX_PATH] = {0};
1045 WCHAR cCurrDirW [MAX_PATH];
1046 static WCHAR cTestDirW[] = {'t','e','s','t','d','i','r',0};
1047 IShellFolder *IDesktopFolder, *testIShellFolder;
1048 ITEMIDLIST *newPIDL;
1050 BOOL foundFlagsMatch;
1052 hr = SHGetDesktopFolder(&psfDesktop);
1053 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1054 if (hr != S_OK) return;
1056 /* The Desktop attributes can be queried with a single empty itemidlist, .. */
1057 dwFlags = 0xffffffff;
1058 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, &pidlEmpty, &dwFlags);
1059 ok (hr == S_OK, "Desktop->GetAttributesOf(empty pidl) failed! hr = %08x\n", hr);
1060 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1061 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
1063 if (desktopFlags[i] == dwFlags)
1064 foundFlagsMatch = TRUE;
1066 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
1068 /* .. or with no itemidlist at all. */
1069 dwFlags = 0xffffffff;
1070 hr = IShellFolder_GetAttributesOf(psfDesktop, 0, NULL, &dwFlags);
1071 ok (hr == S_OK, "Desktop->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
1072 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1073 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
1075 if (desktopFlags[i] == dwFlags)
1076 foundFlagsMatch = TRUE;
1078 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
1080 /* Testing the attributes of the MyComputer shellfolder */
1081 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1082 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1084 IShellFolder_Release(psfDesktop);
1088 /* Windows sets the SFGAO_CANLINK flag, when MyComputer is queried via the Desktop
1089 * folder object. It doesn't do this, if MyComputer is queried directly (see below).
1091 dwFlags = 0xffffffff;
1092 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, (LPCITEMIDLIST*)&pidlMyComputer, &dwFlags);
1093 ok (hr == S_OK, "Desktop->GetAttributesOf(MyComputer) failed! hr = %08x\n", hr);
1094 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1095 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
1097 if ((myComputerFlags[i] | SFGAO_CANLINK) == dwFlags)
1098 foundFlagsMatch = TRUE;
1101 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
1103 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
1104 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
1105 IShellFolder_Release(psfDesktop);
1106 IMalloc_Free(ppM, pidlMyComputer);
1107 if (hr != S_OK) return;
1109 hr = IShellFolder_GetAttributesOf(psfMyComputer, 1, &pidlEmpty, &dwFlags);
1111 ok (hr == E_INVALIDARG ||
1112 broken(hr == S_OK), /* W2K and earlier */
1113 "MyComputer->GetAttributesOf(emtpy pidl) should fail! hr = %08x\n", hr);
1115 dwFlags = 0xffffffff;
1116 hr = IShellFolder_GetAttributesOf(psfMyComputer, 0, NULL, &dwFlags);
1117 ok (hr == S_OK, "MyComputer->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
1118 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1119 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
1121 if (myComputerFlags[i] == dwFlags)
1122 foundFlagsMatch = TRUE;
1125 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
1127 IShellFolder_Release(psfMyComputer);
1129 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1130 len = lstrlenA(cCurrDirA);
1133 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_GetAttributesOf\n");
1136 if (len > 3 && cCurrDirA[len-1] == '\\')
1137 cCurrDirA[len-1] = 0;
1139 /* create test directory */
1140 CreateFilesFolders();
1142 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1144 hr = SHGetDesktopFolder(&IDesktopFolder);
1145 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1147 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1148 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1150 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1151 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1153 IMalloc_Free(ppM, newPIDL);
1155 /* get relative PIDL */
1156 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1157 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1159 /* test the shell attributes of the test directory using the relative PIDL */
1160 dwFlags = SFGAO_FOLDER;
1161 hr = IShellFolder_GetAttributesOf(testIShellFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
1162 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
1163 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for relative PIDL: %08x\n", dwFlags);
1166 IMalloc_Free(ppM, newPIDL);
1168 /* append testdirectory name to path */
1169 if (cCurrDirA[len-1] == '\\')
1170 cCurrDirA[len-1] = 0;
1171 lstrcatA(cCurrDirA, "\\testdir");
1172 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1174 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1175 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1177 /* test the shell attributes of the test directory using the absolute PIDL */
1178 dwFlags = SFGAO_FOLDER;
1179 hr = IShellFolder_GetAttributesOf(IDesktopFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
1180 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
1181 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for absolute PIDL: %08x\n", dwFlags);
1184 IMalloc_Free(ppM, newPIDL);
1186 IShellFolder_Release(testIShellFolder);
1190 IShellFolder_Release(IDesktopFolder);
1193 static void test_SHGetPathFromIDList(void)
1195 SHITEMID emptyitem = { 0, { 0 } };
1196 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
1197 LPITEMIDLIST pidlMyComputer;
1198 WCHAR wszPath[MAX_PATH], wszDesktop[MAX_PATH];
1201 LPSHELLFOLDER psfDesktop;
1202 WCHAR wszMyComputer[] = {
1203 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
1204 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
1205 WCHAR wszFileName[MAX_PATH];
1206 LPITEMIDLIST pidlTestFile;
1209 static WCHAR wszTestFile[] = {
1210 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
1211 LPITEMIDLIST pidlPrograms;
1213 if(!pSHGetPathFromIDListW || !pSHGetSpecialFolderPathW)
1215 win_skip("SHGetPathFromIDListW() or SHGetSpecialFolderPathW() is missing\n");
1219 /* Calling SHGetPathFromIDListW with no pidl should return the empty string */
1222 result = pSHGetPathFromIDListW(NULL, wszPath);
1223 ok(!result, "Expected failure\n");
1224 ok(!wszPath[0], "Expected empty string\n");
1226 /* Calling SHGetPathFromIDListW with an empty pidl should return the desktop folder's path. */
1227 result = pSHGetSpecialFolderPathW(NULL, wszDesktop, CSIDL_DESKTOP, FALSE);
1228 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOP) failed! Last error: %u\n", GetLastError());
1229 if (!result) return;
1231 /* Check if we are on Win9x */
1232 SetLastError(0xdeadbeef);
1233 lstrcmpiW(wszDesktop, wszDesktop);
1234 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1236 win_skip("Most W-calls are not implemented\n");
1240 result = pSHGetPathFromIDListW(pidlEmpty, wszPath);
1241 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1242 if (!result) return;
1243 ok(!lstrcmpiW(wszDesktop, wszPath), "SHGetPathFromIDListW didn't return desktop path for empty pidl!\n");
1245 /* MyComputer does not map to a filesystem path. SHGetPathFromIDListW should fail. */
1246 hr = SHGetDesktopFolder(&psfDesktop);
1247 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1248 if (hr != S_OK) return;
1250 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1251 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1253 IShellFolder_Release(psfDesktop);
1257 SetLastError(0xdeadbeef);
1260 result = pSHGetPathFromIDListW(pidlMyComputer, wszPath);
1261 ok (!result, "SHGetPathFromIDListW succeeded where it shouldn't!\n");
1262 ok (GetLastError()==0xdeadbeef ||
1263 GetLastError()==ERROR_SUCCESS, /* Vista and higher */
1264 "Unexpected last error from SHGetPathFromIDListW: %u\n", GetLastError());
1265 ok (!wszPath[0], "Expected empty path\n");
1267 IShellFolder_Release(psfDesktop);
1271 IMalloc_Free(ppM, pidlMyComputer);
1273 result = pSHGetSpecialFolderPathW(NULL, wszFileName, CSIDL_DESKTOPDIRECTORY, FALSE);
1274 ok(result, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1276 IShellFolder_Release(psfDesktop);
1279 myPathAddBackslashW(wszFileName);
1280 lstrcatW(wszFileName, wszTestFile);
1281 hTestFile = CreateFileW(wszFileName, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
1282 ok(hTestFile != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: %u\n", GetLastError());
1283 if (hTestFile == INVALID_HANDLE_VALUE) {
1284 IShellFolder_Release(psfDesktop);
1287 CloseHandle(hTestFile);
1289 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
1290 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse filename hr = %08x\n", hr);
1292 IShellFolder_Release(psfDesktop);
1293 DeleteFileW(wszFileName);
1294 IMalloc_Free(ppM, pidlTestFile);
1298 /* This test is to show that the Desktop shellfolder prepends the CSIDL_DESKTOPDIRECTORY
1299 * path for files placed on the desktop, if called with SHGDN_FORPARSING. */
1300 hr = IShellFolder_GetDisplayNameOf(psfDesktop, pidlTestFile, SHGDN_FORPARSING, &strret);
1301 ok (hr == S_OK, "Desktop's GetDisplayNamfOf failed! hr = %08x\n", hr);
1302 IShellFolder_Release(psfDesktop);
1303 DeleteFileW(wszFileName);
1305 IMalloc_Free(ppM, pidlTestFile);
1310 pStrRetToBufW(&strret, pidlTestFile, wszPath, MAX_PATH);
1311 ok(0 == lstrcmpW(wszFileName, wszPath),
1312 "Desktop->GetDisplayNameOf(pidlTestFile, SHGDN_FORPARSING) "
1313 "returned incorrect path for file placed on desktop\n");
1316 result = pSHGetPathFromIDListW(pidlTestFile, wszPath);
1317 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1318 IMalloc_Free(ppM, pidlTestFile);
1319 if (!result) return;
1320 ok(0 == lstrcmpW(wszFileName, wszPath), "SHGetPathFromIDListW returned incorrect path for file placed on desktop\n");
1323 /* Test if we can get the path from the start menu "program files" PIDL. */
1324 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidlPrograms);
1325 ok(hr == S_OK, "SHGetFolderLocation failed: 0x%08x\n", hr);
1327 SetLastError(0xdeadbeef);
1328 result = pSHGetPathFromIDListW(pidlPrograms, wszPath);
1329 IMalloc_Free(ppM, pidlPrograms);
1330 ok(result, "SHGetPathFromIDListW failed\n");
1333 static void test_EnumObjects_and_CompareIDs(void)
1335 ITEMIDLIST *newPIDL;
1336 IShellFolder *IDesktopFolder, *testIShellFolder;
1337 char cCurrDirA [MAX_PATH] = {0};
1338 static const CHAR cTestDirA[] = "\\testdir";
1339 WCHAR cTestDirW[MAX_PATH];
1343 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1344 len = lstrlenA(cCurrDirA);
1347 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_EnumObjects_and_CompareIDs\n");
1350 if(cCurrDirA[len-1] == '\\')
1351 cCurrDirA[len-1] = 0;
1353 lstrcatA(cCurrDirA, cTestDirA);
1354 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cTestDirW, MAX_PATH);
1356 hr = SHGetDesktopFolder(&IDesktopFolder);
1357 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1359 CreateFilesFolders();
1361 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1362 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1364 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1365 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1367 test_EnumObjects(testIShellFolder);
1369 IShellFolder_Release(testIShellFolder);
1373 IMalloc_Free(ppM, newPIDL);
1375 IShellFolder_Release(IDesktopFolder);
1378 /* A simple implementation of an IPropertyBag, which returns fixed values for
1379 * 'Target' and 'Attributes' properties.
1381 static HRESULT WINAPI InitPropertyBag_IPropertyBag_QueryInterface(IPropertyBag *iface, REFIID riid,
1385 return E_INVALIDARG;
1387 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPropertyBag, riid)) {
1390 ok (FALSE, "InitPropertyBag asked for unknown interface!\n");
1391 return E_NOINTERFACE;
1394 IPropertyBag_AddRef(iface);
1398 static ULONG WINAPI InitPropertyBag_IPropertyBag_AddRef(IPropertyBag *iface) {
1402 static ULONG WINAPI InitPropertyBag_IPropertyBag_Release(IPropertyBag *iface) {
1406 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Read(IPropertyBag *iface, LPCOLESTR pszPropName,
1407 VARIANT *pVar, IErrorLog *pErrorLog)
1409 static const WCHAR wszTargetSpecialFolder[] = {
1410 'T','a','r','g','e','t','S','p','e','c','i','a','l','F','o','l','d','e','r',0 };
1411 static const WCHAR wszTarget[] = {
1412 'T','a','r','g','e','t',0 };
1413 static const WCHAR wszAttributes[] = {
1414 'A','t','t','r','i','b','u','t','e','s',0 };
1415 static const WCHAR wszResolveLinkFlags[] = {
1416 'R','e','s','o','l','v','e','L','i','n','k','F','l','a','g','s',0 };
1417 static const WCHAR wszTargetKnownFolder[] = {
1418 'T','a','r','g','e','t','K','n','o','w','n','F','o','l','d','e','r',0 };
1419 static const WCHAR wszCLSID[] = {
1420 'C','L','S','I','D',0 };
1422 if (!lstrcmpW(pszPropName, wszTargetSpecialFolder)) {
1423 ok(V_VT(pVar) == VT_I4 ||
1424 broken(V_VT(pVar) == VT_BSTR), /* Win2k */
1425 "Wrong variant type for 'TargetSpecialFolder' property!\n");
1426 return E_INVALIDARG;
1429 if (!lstrcmpW(pszPropName, wszResolveLinkFlags))
1431 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'ResolveLinkFlags' property!\n");
1432 return E_INVALIDARG;
1435 if (!lstrcmpW(pszPropName, wszTarget)) {
1436 WCHAR wszPath[MAX_PATH];
1439 ok(V_VT(pVar) == VT_BSTR ||
1440 broken(V_VT(pVar) == VT_EMPTY), /* Win2k */
1441 "Wrong variant type for 'Target' property!\n");
1442 if (V_VT(pVar) != VT_BSTR) return E_INVALIDARG;
1444 result = pSHGetSpecialFolderPathW(NULL, wszPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1445 ok(result, "SHGetSpecialFolderPathW(DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1446 if (!result) return E_INVALIDARG;
1448 V_BSTR(pVar) = SysAllocString(wszPath);
1452 if (!lstrcmpW(pszPropName, wszAttributes)) {
1453 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'Attributes' property!\n");
1454 if (V_VT(pVar) != VT_UI4) return E_INVALIDARG;
1455 V_UI4(pVar) = SFGAO_FOLDER|SFGAO_HASSUBFOLDER|SFGAO_FILESYSANCESTOR|
1456 SFGAO_CANRENAME|SFGAO_FILESYSTEM;
1460 if (!lstrcmpW(pszPropName, wszTargetKnownFolder)) {
1461 ok(V_VT(pVar) == VT_BSTR, "Wrong variant type for 'TargetKnownFolder' property!\n");
1463 return E_INVALIDARG;
1466 if (!lstrcmpW(pszPropName, wszCLSID)) {
1467 ok(V_VT(pVar) == VT_EMPTY, "Wrong variant type for 'CLSID' property!\n");
1469 return E_INVALIDARG;
1472 ok(FALSE, "PropertyBag was asked for unknown property %s (vt=%d)!\n", wine_dbgstr_w(pszPropName), V_VT(pVar));
1473 return E_INVALIDARG;
1476 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Write(IPropertyBag *iface, LPCOLESTR pszPropName,
1479 ok(FALSE, "Unexpected call to IPropertyBag_Write\n");
1483 static const IPropertyBagVtbl InitPropertyBag_IPropertyBagVtbl = {
1484 InitPropertyBag_IPropertyBag_QueryInterface,
1485 InitPropertyBag_IPropertyBag_AddRef,
1486 InitPropertyBag_IPropertyBag_Release,
1487 InitPropertyBag_IPropertyBag_Read,
1488 InitPropertyBag_IPropertyBag_Write
1491 static struct IPropertyBag InitPropertyBag = {
1492 &InitPropertyBag_IPropertyBagVtbl
1495 static void test_FolderShortcut(void) {
1496 IPersistPropertyBag *pPersistPropertyBag;
1497 IShellFolder *pShellFolder, *pDesktopFolder;
1498 IPersistFolder3 *pPersistFolder3;
1501 WCHAR wszDesktopPath[MAX_PATH], wszBuffer[MAX_PATH];
1504 LPITEMIDLIST pidlCurrentFolder, pidlWineTestFolder, pidlSubFolder;
1506 WCHAR wszWineTestFolder[] = {
1507 ':',':','{','9','B','3','5','2','E','B','F','-','2','7','6','5','-','4','5','C','1','-',
1508 'B','4','C','6','-','8','5','C','C','7','F','7','A','B','C','6','4','}',0 };
1509 WCHAR wszShellExtKey[] = { 'S','o','f','t','w','a','r','e','\\',
1510 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
1511 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1512 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
1513 'N','a','m','e','S','p','a','c','e','\\',
1514 '{','9','b','3','5','2','e','b','f','-','2','7','6','5','-','4','5','c','1','-',
1515 'b','4','c','6','-','8','5','c','c','7','f','7','a','b','c','6','4','}',0 };
1517 WCHAR wszSomeSubFolder[] = { 'S','u','b','F','o','l','d','e','r', 0};
1518 static const GUID CLSID_UnixDosFolder =
1519 {0x9d20aae8, 0x0625, 0x44b0, {0x9c, 0xa7, 0x71, 0x88, 0x9c, 0x22, 0x54, 0xd9}};
1521 if (!pSHGetSpecialFolderPathW || !pStrRetToBufW) {
1522 win_skip("SHGetSpecialFolderPathW and/or StrRetToBufW are not available\n");
1526 if (!pSHGetFolderPathAndSubDirA)
1528 win_skip("FolderShortcut test doesn't work on Win2k\n");
1532 /* These tests basically show, that CLSID_FolderShortcuts are initialized
1533 * via their IPersistPropertyBag interface. And that the target folder
1534 * is taken from the IPropertyBag's 'Target' property.
1536 hr = CoCreateInstance(&CLSID_FolderShortcut, NULL, CLSCTX_INPROC_SERVER,
1537 &IID_IPersistPropertyBag, (LPVOID*)&pPersistPropertyBag);
1538 if (hr == REGDB_E_CLASSNOTREG) {
1539 win_skip("CLSID_FolderShortcut is not implemented\n");
1542 ok (hr == S_OK, "CoCreateInstance failed! hr = 0x%08x\n", hr);
1543 if (hr != S_OK) return;
1545 hr = IPersistPropertyBag_Load(pPersistPropertyBag, &InitPropertyBag, NULL);
1546 ok(hr == S_OK, "IPersistPropertyBag_Load failed! hr = %08x\n", hr);
1548 IPersistPropertyBag_Release(pPersistPropertyBag);
1552 hr = IPersistPropertyBag_QueryInterface(pPersistPropertyBag, &IID_IShellFolder,
1553 (LPVOID*)&pShellFolder);
1554 IPersistPropertyBag_Release(pPersistPropertyBag);
1555 ok(hr == S_OK, "IPersistPropertyBag_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1556 if (hr != S_OK) return;
1558 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1559 ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1561 IShellFolder_Release(pShellFolder);
1565 result = pSHGetSpecialFolderPathW(NULL, wszDesktopPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1566 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1567 if (!result) return;
1569 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1570 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1572 hr = IShellFolder_QueryInterface(pShellFolder, &IID_IPersistFolder3, (LPVOID*)&pPersistFolder3);
1573 IShellFolder_Release(pShellFolder);
1574 ok(hr == S_OK, "IShellFolder_QueryInterface(IID_IPersistFolder3 failed! hr = 0x%08x\n", hr);
1575 if (hr != S_OK) return;
1577 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1578 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1579 ok(IsEqualCLSID(&clsid, &CLSID_FolderShortcut), "Unexpected CLSID!\n");
1581 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1582 todo_wine ok(hr == S_FALSE, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1583 ok(!pidlCurrentFolder, "IPersistFolder3_GetCurFolder should return a NULL pidl!\n");
1585 /* For FolderShortcut objects, the Initialize method initialized the folder's position in the
1586 * shell namespace. The target folder, read from the property bag above, remains untouched.
1587 * The following tests show this: The itemidlist for some imaginary shellfolder object
1588 * is created and the FolderShortcut is initialized with it. GetCurFolder now returns this
1589 * itemidlist, but GetDisplayNameOf still returns the path from above.
1591 hr = SHGetDesktopFolder(&pDesktopFolder);
1592 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1593 if (hr != S_OK) return;
1595 /* Temporarily register WineTestFolder as a shell namespace extension at the Desktop.
1596 * Otherwise ParseDisplayName fails on WinXP with E_INVALIDARG */
1597 RegCreateKeyW(HKEY_CURRENT_USER, wszShellExtKey, &hShellExtKey);
1598 RegCloseKey(hShellExtKey);
1599 hr = IShellFolder_ParseDisplayName(pDesktopFolder, NULL, NULL, wszWineTestFolder, NULL,
1600 &pidlWineTestFolder, NULL);
1601 RegDeleteKeyW(HKEY_CURRENT_USER, wszShellExtKey);
1602 IShellFolder_Release(pDesktopFolder);
1603 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1604 if (hr != S_OK) return;
1606 hr = IPersistFolder3_Initialize(pPersistFolder3, pidlWineTestFolder);
1607 ok (hr == S_OK, "IPersistFolder3::Initialize failed! hr = %08x\n", hr);
1609 IPersistFolder3_Release(pPersistFolder3);
1610 pILFree(pidlWineTestFolder);
1614 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1615 ok(hr == S_OK, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1616 ok(pILIsEqual(pidlCurrentFolder, pidlWineTestFolder),
1617 "IPersistFolder3_GetCurFolder should return pidlWineTestFolder!\n");
1618 pILFree(pidlCurrentFolder);
1619 pILFree(pidlWineTestFolder);
1621 hr = IPersistFolder3_QueryInterface(pPersistFolder3, &IID_IShellFolder, (LPVOID*)&pShellFolder);
1622 IPersistFolder3_Release(pPersistFolder3);
1623 ok(hr == S_OK, "IPersistFolder3_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1624 if (hr != S_OK) return;
1626 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1627 ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1629 IShellFolder_Release(pShellFolder);
1633 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1634 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1636 /* Next few lines are meant to show that children of FolderShortcuts are not FolderShortcuts,
1637 * but ShellFSFolders. */
1638 myPathAddBackslashW(wszDesktopPath);
1639 lstrcatW(wszDesktopPath, wszSomeSubFolder);
1640 if (!CreateDirectoryW(wszDesktopPath, NULL)) {
1641 IShellFolder_Release(pShellFolder);
1645 hr = IShellFolder_ParseDisplayName(pShellFolder, NULL, NULL, wszSomeSubFolder, NULL,
1646 &pidlSubFolder, NULL);
1647 RemoveDirectoryW(wszDesktopPath);
1648 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1650 IShellFolder_Release(pShellFolder);
1654 hr = IShellFolder_BindToObject(pShellFolder, pidlSubFolder, NULL, &IID_IPersistFolder3,
1655 (LPVOID*)&pPersistFolder3);
1656 IShellFolder_Release(pShellFolder);
1657 pILFree(pidlSubFolder);
1658 ok (hr == S_OK, "IShellFolder::BindToObject failed! hr = %08x\n", hr);
1662 /* On windows, we expect CLSID_ShellFSFolder. On wine we relax this constraint
1663 * a little bit and also allow CLSID_UnixDosFolder. */
1664 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1665 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1666 ok(IsEqualCLSID(&clsid, &CLSID_ShellFSFolder) || IsEqualCLSID(&clsid, &CLSID_UnixDosFolder),
1667 "IPersistFolder3::GetClassID returned unexpected CLSID!\n");
1669 IPersistFolder3_Release(pPersistFolder3);
1672 #include "pshpack1.h"
1673 struct FileStructA {
1677 WORD uFileDate; /* In our current implementation this is */
1678 WORD uFileTime; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastWriteTime) */
1683 struct FileStructW {
1684 WORD cbLen; /* Length of this element. */
1685 BYTE abFooBar1[6]; /* Beyond any recognition. */
1686 WORD uDate; /* FileTimeToDosDate(WIN32_FIND_DATA->ftCreationTime)? */
1687 WORD uTime; /* (this is currently speculation) */
1688 WORD uDate2; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastAccessTime)? */
1689 WORD uTime2; /* (this is currently speculation) */
1690 BYTE abFooBar2[4]; /* Beyond any recognition. */
1691 WCHAR wszName[1]; /* The long filename in unicode. */
1692 /* Just for documentation: Right after the unicode string: */
1693 WORD cbOffset; /* FileStructW's offset from the beginning of the SHITMEID.
1694 * SHITEMID->cb == uOffset + cbLen */
1696 #include "poppack.h"
1698 static void test_ITEMIDLIST_format(void) {
1699 WCHAR wszPersonal[MAX_PATH];
1700 LPSHELLFOLDER psfDesktop, psfPersonal;
1701 LPITEMIDLIST pidlPersonal, pidlFile;
1705 WCHAR wszFile[3][17] = { { 'e','v','e','n','_',0 }, { 'o','d','d','_',0 },
1706 { 'l','o','n','g','e','r','_','t','h','a','n','.','8','_','3',0 } };
1709 if (!pSHGetSpecialFolderPathW) return;
1711 bResult = pSHGetSpecialFolderPathW(NULL, wszPersonal, CSIDL_PERSONAL, FALSE);
1712 ok(bResult, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1713 if (!bResult) return;
1715 SetLastError(0xdeadbeef);
1716 bResult = SetCurrentDirectoryW(wszPersonal);
1717 if (!bResult && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
1718 win_skip("Most W-calls are not implemented\n");
1721 ok(bResult, "SetCurrentDirectory failed! Last error: %u\n", GetLastError());
1722 if (!bResult) return;
1724 hr = SHGetDesktopFolder(&psfDesktop);
1725 ok(hr == S_OK, "SHGetDesktopFolder failed! hr: %08x\n", hr);
1726 if (hr != S_OK) return;
1728 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszPersonal, NULL, &pidlPersonal, NULL);
1729 ok(hr == S_OK, "psfDesktop->ParseDisplayName failed! hr = %08x\n", hr);
1731 IShellFolder_Release(psfDesktop);
1735 hr = IShellFolder_BindToObject(psfDesktop, pidlPersonal, NULL, &IID_IShellFolder,
1736 (LPVOID*)&psfPersonal);
1737 IShellFolder_Release(psfDesktop);
1738 pILFree(pidlPersonal);
1739 ok(hr == S_OK, "psfDesktop->BindToObject failed! hr = %08x\n", hr);
1740 if (hr != S_OK) return;
1742 for (i=0; i<3; i++) {
1743 CHAR szFile[MAX_PATH];
1744 struct FileStructA *pFileStructA;
1747 WideCharToMultiByte(CP_ACP, 0, wszFile[i], -1, szFile, MAX_PATH, NULL, NULL);
1749 hFile = CreateFileW(wszFile[i], GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_FLAG_WRITE_THROUGH, NULL);
1750 ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed! (%u)\n", GetLastError());
1751 if (hFile == INVALID_HANDLE_VALUE) {
1752 IShellFolder_Release(psfPersonal);
1757 hr = IShellFolder_ParseDisplayName(psfPersonal, NULL, NULL, wszFile[i], NULL, &pidlFile, NULL);
1758 DeleteFileW(wszFile[i]);
1759 ok(hr == S_OK, "psfPersonal->ParseDisplayName failed! hr: %08x\n", hr);
1761 IShellFolder_Release(psfPersonal);
1765 pFileStructA = (struct FileStructA *)pidlFile->mkid.abID;
1766 ok(pFileStructA->type == 0x32, "PIDLTYPE should be 0x32!\n");
1767 ok(pFileStructA->dummy == 0x00, "Dummy Byte should be 0x00!\n");
1768 ok(pFileStructA->dwFileSize == 0, "Filesize should be zero!\n");
1770 if (i < 2) /* First two file names are already in valid 8.3 format */
1771 ok(!strcmp(szFile, (CHAR*)&pidlFile->mkid.abID[12]), "Wrong file name!\n");
1773 /* WinXP stores a derived 8.3 dos name (LONGER~1.8_3) here. We probably
1774 * can't implement this correctly, since unix filesystems don't support
1775 * this nasty short/long filename stuff. So we'll probably stay with our
1776 * current habbit of storing the long filename here, which seems to work
1779 ok(pidlFile->mkid.abID[18] == '~' ||
1780 broken(pidlFile->mkid.abID[34] == '~'), /* Win2k */
1781 "Should be derived 8.3 name!\n");
1783 if (i == 0) /* First file name has an even number of chars. No need for alignment. */
1784 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] != '\0' ||
1785 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1), /* Win2k */
1786 "Alignment byte, where there shouldn't be!\n");
1788 if (i == 1) /* Second file name has an uneven number of chars => alignment byte */
1789 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] == '\0',
1790 "There should be an alignment byte, but isn't!\n");
1792 /* The offset of the FileStructW member is stored as a WORD at the end of the pidl. */
1793 cbOffset = *(WORD*)(((LPBYTE)pidlFile)+pidlFile->mkid.cb-sizeof(WORD));
1794 ok ((cbOffset >= sizeof(struct FileStructA) &&
1795 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW)) ||
1796 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1) || /* Win2k on short names */
1797 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 12 + 1), /* Win2k on long names */
1798 "Wrong offset value (%d) stored at the end of the PIDL\n", cbOffset);
1800 if (cbOffset >= sizeof(struct FileStructA) &&
1801 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW))
1803 struct FileStructW *pFileStructW = (struct FileStructW *)(((LPBYTE)pidlFile)+cbOffset);
1805 ok(pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen,
1806 "FileStructW's offset and length should add up to the PIDL's length!\n");
1808 if (pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen) {
1809 /* Since we just created the file, time of creation,
1810 * time of last access and time of last write access just be the same.
1811 * These tests seem to fail sometimes (on WinXP), if the test is run again shortly
1812 * after the first run. I do remember something with NTFS keeping the creation time
1813 * if a file is deleted and then created again within a couple of seconds or so.
1814 * Might be the reason. */
1815 ok (pFileStructA->uFileDate == pFileStructW->uDate &&
1816 pFileStructA->uFileTime == pFileStructW->uTime,
1817 "Last write time should match creation time!\n");
1819 /* On FAT filesystems the last access time is midnight
1820 local time, so the values of uDate2 and uTime2 will
1821 depend on the local timezone. If the times are exactly
1822 equal then the dates should be identical for both FAT
1823 and NTFS as no timezone is more than 1 day away from UTC.
1825 if (pFileStructA->uFileTime == pFileStructW->uTime2)
1827 ok (pFileStructA->uFileDate == pFileStructW->uDate2,
1828 "Last write date and time should match last access date and time!\n");
1832 /* Filesystem may be FAT. Check date within 1 day
1833 and seconds are zero. */
1834 trace ("Filesystem may be FAT. Performing less strict atime test.\n");
1835 ok ((pFileStructW->uTime2 & 0x1F) == 0,
1836 "Last access time on FAT filesystems should have zero seconds.\n");
1837 /* TODO: Perform check for date being within one day.*/
1840 ok (!lstrcmpW(wszFile[i], pFileStructW->wszName) ||
1841 !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 22)) || /* Vista */
1842 !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 26)), /* Win7 */
1843 "The filename should be stored in unicode at this position!\n");
1850 IShellFolder_Release(psfPersonal);
1853 static void test_SHGetFolderPathA(void)
1855 static const BOOL is_win64 = sizeof(void *) > sizeof(int);
1857 char path[MAX_PATH];
1858 char path_x86[MAX_PATH];
1859 char path_key[MAX_PATH];
1863 if (!pSHGetFolderPathA)
1865 win_skip("SHGetFolderPathA not present\n");
1868 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
1870 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES, 0, SHGFP_TYPE_CURRENT, path );
1871 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1872 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILESX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
1875 win_skip( "Program Files (x86) not supported\n" );
1878 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1881 ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1882 ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1883 ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1887 ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1889 ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1891 ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1893 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1895 DWORD type, count = sizeof(path_x86);
1896 if (!RegQueryValueExA( key, "ProgramFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1898 ok( is_win64 || is_wow64, "ProgramFilesDir (x86) exists on 32-bit setup\n" );
1899 ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1901 else ok( !is_win64 && !is_wow64, "ProgramFilesDir (x86) should exist on 64-bit setup\n" );
1905 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMON, 0, SHGFP_TYPE_CURRENT, path );
1906 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1907 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMONX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
1910 win_skip( "Common Files (x86) not supported\n" );
1913 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1916 ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1917 ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1918 ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1922 ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1924 ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1926 ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1928 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1930 DWORD type, count = sizeof(path_x86);
1931 if (!RegQueryValueExA( key, "CommonFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1933 ok( is_win64 || is_wow64, "CommonFilesDir (x86) exists on 32-bit setup\n" );
1934 ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1936 else ok( !is_win64 && !is_wow64, "CommonFilesDir (x86) should exist on 64-bit setup\n" );
1940 static void test_SHGetFolderPathAndSubDirA(void)
1946 static char wine[] = "wine";
1947 static char winetemp[] = "wine\\temp";
1948 static char appdata[MAX_PATH];
1949 static char testpath[MAX_PATH];
1950 static char toolongpath[MAX_PATH+1];
1952 if(!pSHGetFolderPathAndSubDirA)
1954 win_skip("SHGetFolderPathAndSubDirA not present!\n");
1958 if(!pSHGetFolderPathA) {
1959 win_skip("SHGetFolderPathA not present!\n");
1962 if(FAILED(pSHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdata)))
1964 win_skip("SHGetFolderPathA failed for CSIDL_LOCAL_APPDATA!\n");
1968 sprintf(testpath, "%s\\%s", appdata, winetemp);
1969 delret = RemoveDirectoryA(testpath);
1970 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) ) {
1971 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1975 sprintf(testpath, "%s\\%s", appdata, wine);
1976 delret = RemoveDirectoryA(testpath);
1977 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) && (ERROR_FILE_NOT_FOUND != GetLastError())) {
1978 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1982 /* test invalid second parameter */
1983 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | 0xff, NULL, SHGFP_TYPE_CURRENT, wine, testpath);
1984 ok(E_INVALIDARG == ret, "expected E_INVALIDARG, got %x\n", ret);
1986 /* test fourth parameter */
1987 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, 2, winetemp, testpath);
1989 case S_OK: /* winvista */
1990 ok(!strncmp(appdata, testpath, strlen(appdata)),
1991 "expected %s to start with %s\n", testpath, appdata);
1992 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1993 "expected %s to end with %s\n", testpath, winetemp);
1995 case E_INVALIDARG: /* winxp, win2k3 */
1998 ok(0, "expected S_OK or E_INVALIDARG, got %x\n", ret);
2001 /* test fifth parameter */
2003 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, NULL, testpath);
2004 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2005 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2008 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "", testpath);
2009 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2010 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2013 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "\\", testpath);
2014 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2015 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2017 for(i=0; i< MAX_PATH; i++)
2018 toolongpath[i] = '0' + i % 10;
2019 toolongpath[MAX_PATH] = '\0';
2020 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, toolongpath, testpath);
2021 ok(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) == ret,
2022 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), ret);
2025 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wine, NULL);
2026 ok((S_OK == ret) || (E_INVALIDARG == ret), "expected S_OK or E_INVALIDARG, got %x\n", ret);
2028 /* test a not existing path */
2030 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
2031 ok(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == ret,
2032 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), ret);
2034 /* create a directory inside a not existing directory */
2036 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_CREATE | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
2037 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2038 ok(!strncmp(appdata, testpath, strlen(appdata)),
2039 "expected %s to start with %s\n", testpath, appdata);
2040 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
2041 "expected %s to end with %s\n", testpath, winetemp);
2042 dwret = GetFileAttributes(testpath);
2043 ok(FILE_ATTRIBUTE_DIRECTORY | dwret, "expected %x to contain FILE_ATTRIBUTE_DIRECTORY\n", dwret);
2046 sprintf(testpath, "%s\\%s", appdata, winetemp);
2047 RemoveDirectoryA(testpath);
2048 sprintf(testpath, "%s\\%s", appdata, wine);
2049 RemoveDirectoryA(testpath);
2052 static void test_LocalizedNames(void)
2054 static char cCurrDirA[MAX_PATH];
2055 WCHAR cCurrDirW[MAX_PATH], tempbufW[25];
2056 IShellFolder *IDesktopFolder, *testIShellFolder;
2057 ITEMIDLIST *newPIDL;
2060 static char resourcefile[MAX_PATH];
2066 static const char desktopini_contents1[] =
2067 "[.ShellClassInfo]\r\n"
2068 "LocalizedResourceName=@";
2069 static const char desktopini_contents2[] =
2071 static WCHAR foldernameW[] = {'t','e','s','t','f','o','l','d','e','r',0};
2072 static const WCHAR folderdisplayW[] = {'F','o','l','d','e','r',' ','N','a','m','e',' ','R','e','s','o','u','r','c','e',0};
2074 /* create folder with desktop.ini and localized name in GetModuleFileNameA(NULL) */
2075 CreateDirectoryA(".\\testfolder", NULL);
2077 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")|FILE_ATTRIBUTE_SYSTEM);
2079 GetModuleFileNameA(NULL, resourcefile, MAX_PATH);
2081 file = CreateFileA(".\\testfolder\\desktop.ini", GENERIC_WRITE, 0, NULL,
2082 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2083 ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %i\n", GetLastError());
2084 ret = WriteFile(file, desktopini_contents1, strlen(desktopini_contents1), &res, NULL) &&
2085 WriteFile(file, resourcefile, strlen(resourcefile), &res, NULL) &&
2086 WriteFile(file, desktopini_contents2, strlen(desktopini_contents2), &res, NULL);
2087 ok(ret, "WriteFile failed %i\n", GetLastError());
2090 /* get IShellFolder for parent */
2091 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
2092 len = lstrlenA(cCurrDirA);
2095 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_LocalizedNames\n");
2098 if(cCurrDirA[len-1] == '\\')
2099 cCurrDirA[len-1] = 0;
2101 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
2103 hr = SHGetDesktopFolder(&IDesktopFolder);
2104 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
2106 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
2107 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
2109 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
2110 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
2112 IMalloc_Free(ppM, newPIDL);
2114 /* windows reads the display name from the resource */
2115 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, foldernameW, NULL, &newPIDL, 0);
2116 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
2118 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER, &strret);
2119 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2121 if (hr == S_OK && pStrRetToBufW)
2123 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2124 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2126 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
2127 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
2128 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2131 /* editing name is also read from the resource */
2132 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FOREDITING, &strret);
2133 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2135 if (hr == S_OK && pStrRetToBufW)
2137 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2138 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2140 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
2141 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
2142 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2145 /* parsing name is unchanged */
2146 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FORPARSING, &strret);
2147 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2149 if (hr == S_OK && pStrRetToBufW)
2151 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2152 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2153 ok (!lstrcmpiW(tempbufW, foldernameW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2156 IShellFolder_Release(IDesktopFolder);
2157 IShellFolder_Release(testIShellFolder);
2159 IMalloc_Free(ppM, newPIDL);
2162 DeleteFileA(".\\testfolder\\desktop.ini");
2163 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")&~FILE_ATTRIBUTE_SYSTEM);
2164 RemoveDirectoryA(".\\testfolder");
2167 static void test_SHCreateShellItem(void)
2169 IShellItem *shellitem, *shellitem2;
2170 IPersistIDList *persistidl;
2171 LPITEMIDLIST pidl_cwd=NULL, pidl_testfile, pidl_abstestfile, pidl_test, pidl_desktop;
2173 char curdirA[MAX_PATH];
2174 WCHAR curdirW[MAX_PATH];
2175 WCHAR fnbufW[MAX_PATH];
2176 IShellFolder *desktopfolder=NULL, *currentfolder=NULL;
2177 static WCHAR testfileW[] = {'t','e','s','t','f','i','l','e',0};
2179 GetCurrentDirectoryA(MAX_PATH, curdirA);
2181 if (!pSHCreateShellItem)
2183 win_skip("SHCreateShellItem isn't available\n");
2187 if (!lstrlenA(curdirA))
2189 win_skip("GetCurrentDirectoryA returned empty string, skipping test_SHCreateShellItem\n");
2193 if(pSHGetSpecialFolderLocation)
2195 ret = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
2196 ok(ret == S_OK, "Got 0x%08x\n", ret);
2200 win_skip("pSHGetSpecialFolderLocation missing.\n");
2201 pidl_desktop = NULL;
2204 MultiByteToWideChar(CP_ACP, 0, curdirA, -1, curdirW, MAX_PATH);
2206 ret = SHGetDesktopFolder(&desktopfolder);
2207 ok(SUCCEEDED(ret), "SHGetShellFolder returned %x\n", ret);
2209 ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2210 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2212 ret = IShellFolder_BindToObject(desktopfolder, pidl_cwd, NULL, &IID_IShellFolder, (void**)¤tfolder);
2213 ok(SUCCEEDED(ret), "BindToObject returned %x\n", ret);
2215 CreateTestFile(".\\testfile");
2217 ret = IShellFolder_ParseDisplayName(currentfolder, NULL, NULL, testfileW, NULL, &pidl_testfile, NULL);
2218 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2220 pidl_abstestfile = pILCombine(pidl_cwd, pidl_testfile);
2222 ret = pSHCreateShellItem(NULL, NULL, NULL, &shellitem);
2223 ok(ret == E_INVALIDARG, "SHCreateShellItem returned %x\n", ret);
2225 if (0) /* crashes on Windows XP */
2227 pSHCreateShellItem(NULL, NULL, pidl_cwd, NULL);
2228 pSHCreateShellItem(pidl_cwd, NULL, NULL, &shellitem);
2229 pSHCreateShellItem(NULL, currentfolder, NULL, &shellitem);
2230 pSHCreateShellItem(pidl_cwd, currentfolder, NULL, &shellitem);
2233 ret = pSHCreateShellItem(NULL, NULL, pidl_cwd, &shellitem);
2234 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2237 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2238 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2241 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2242 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2245 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2248 IPersistIDList_Release(persistidl);
2250 IShellItem_Release(shellitem);
2253 ret = pSHCreateShellItem(pidl_cwd, NULL, pidl_testfile, &shellitem);
2254 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2257 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2258 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2261 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2262 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2265 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2268 IPersistIDList_Release(persistidl);
2271 ret = IShellItem_GetParent(shellitem, &shellitem2);
2272 ok(SUCCEEDED(ret), "GetParent returned %x\n", ret);
2275 ret = IShellItem_QueryInterface(shellitem2, &IID_IPersistIDList, (void**)&persistidl);
2276 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2279 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2280 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2283 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2286 IPersistIDList_Release(persistidl);
2288 IShellItem_Release(shellitem2);
2291 IShellItem_Release(shellitem);
2294 ret = pSHCreateShellItem(NULL, currentfolder, pidl_testfile, &shellitem);
2295 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2298 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2299 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2302 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2303 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2306 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2309 IPersistIDList_Release(persistidl);
2311 IShellItem_Release(shellitem);
2314 /* if a parent pidl and shellfolder are specified, the shellfolder is ignored */
2315 ret = pSHCreateShellItem(pidl_cwd, desktopfolder, pidl_testfile, &shellitem);
2316 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2319 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2320 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2323 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2324 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2327 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2330 IPersistIDList_Release(persistidl);
2332 IShellItem_Release(shellitem);
2335 ret = pSHCreateShellItem(NULL, desktopfolder, pidl_testfile, &shellitem);
2336 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2339 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2340 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2343 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2344 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2347 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2350 IPersistIDList_Release(persistidl);
2353 IShellItem_Release(shellitem);
2356 ret = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
2357 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2360 ret = IShellItem_GetParent(shellitem, &shellitem2);
2361 ok(FAILED(ret), "Got 0x%08x\n", ret);
2362 if(SUCCEEDED(ret)) IShellItem_Release(shellitem2);
2363 IShellItem_Release(shellitem);
2366 /* SHCreateItemFromParsingName */
2367 if(pSHCreateItemFromParsingName)
2371 /* Crashes under windows 7 */
2372 ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, NULL);
2375 shellitem = (void*)0xdeadbeef;
2376 ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, (void**)&shellitem);
2377 ok(ret == E_INVALIDARG, "SHCreateItemFromParsingName returned %x\n", ret);
2378 ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2380 ret = pSHCreateItemFromParsingName(testfileW, NULL, &IID_IShellItem, (void**)&shellitem);
2381 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
2382 "SHCreateItemFromParsingName returned %x\n", ret);
2383 if(SUCCEEDED(ret)) IShellItem_Release(shellitem);
2385 lstrcpyW(fnbufW, curdirW);
2386 myPathAddBackslashW(fnbufW);
2387 lstrcatW(fnbufW, testfileW);
2389 ret = pSHCreateItemFromParsingName(fnbufW, NULL, &IID_IShellItem, (void**)&shellitem);
2390 ok(ret == S_OK, "SHCreateItemFromParsingName returned %x\n", ret);
2394 ret = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &tmp_fname);
2395 ok(ret == S_OK, "GetDisplayName returned %x\n", ret);
2398 ok(!lstrcmpW(fnbufW, tmp_fname), "strings not equal\n");
2399 CoTaskMemFree(tmp_fname);
2401 IShellItem_Release(shellitem);
2405 win_skip("No SHCreateItemFromParsingName\n");
2408 /* SHCreateItemFromIDList */
2409 if(pSHCreateItemFromIDList)
2413 /* Crashes under win7 */
2414 ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, NULL);
2417 ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, (void**)&shellitem);
2418 ok(ret == E_INVALIDARG, "SHCreateItemFromIDList returned %x\n", ret);
2420 ret = pSHCreateItemFromIDList(pidl_cwd, &IID_IShellItem, (void**)&shellitem);
2421 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2424 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2425 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2428 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2429 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2432 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2435 IPersistIDList_Release(persistidl);
2437 IShellItem_Release(shellitem);
2440 ret = pSHCreateItemFromIDList(pidl_testfile, &IID_IShellItem, (void**)&shellitem);
2441 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2444 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2445 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2448 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2449 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2452 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2455 IPersistIDList_Release(persistidl);
2457 IShellItem_Release(shellitem);
2461 win_skip("No SHCreateItemFromIDList\n");
2463 DeleteFileA(".\\testfile");
2464 pILFree(pidl_abstestfile);
2465 pILFree(pidl_testfile);
2466 pILFree(pidl_desktop);
2468 IShellFolder_Release(currentfolder);
2469 IShellFolder_Release(desktopfolder);
2472 static void test_SHGetNameFromIDList(void)
2474 IShellItem *shellitem;
2479 static const DWORD flags[] = {
2480 SIGDN_NORMALDISPLAY, SIGDN_PARENTRELATIVEPARSING,
2481 SIGDN_DESKTOPABSOLUTEPARSING,SIGDN_PARENTRELATIVEEDITING,
2482 SIGDN_DESKTOPABSOLUTEEDITING, /*SIGDN_FILESYSPATH, SIGDN_URL, */
2483 SIGDN_PARENTRELATIVEFORADDRESSBAR,SIGDN_PARENTRELATIVE, -1234};
2485 if(!pSHGetNameFromIDList)
2487 win_skip("SHGetNameFromIDList missing.\n");
2491 /* These should be available on any platform that passed the above test. */
2492 ok(pSHCreateShellItem != NULL, "SHCreateShellItem missing.\n");
2493 ok(pSHBindToParent != NULL, "SHBindToParent missing.\n");
2494 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
2495 ok(pStrRetToBufW != NULL, "StrRetToBufW missing.\n");
2499 /* Crashes under win7 */
2500 hres = pSHGetNameFromIDList(NULL, 0, NULL);
2503 hres = pSHGetNameFromIDList(NULL, 0, &name_string);
2504 ok(hres == E_INVALIDARG, "Got 0x%08x\n", hres);
2506 /* Test the desktop */
2507 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
2508 ok(hres == S_OK, "Got 0x%08x\n", hres);
2509 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2510 ok(hres == S_OK, "Got 0x%08x\n", hres);
2513 WCHAR *nameSI, *nameSH;
2514 WCHAR buf[MAX_PATH];
2515 HRESULT hrSI, hrSH, hrSF;
2520 SHGetDesktopFolder(&psf);
2521 for(i = 0; flags[i] != -1234; i++)
2523 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2524 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2525 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2526 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2527 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2528 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2530 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2531 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2535 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2537 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2539 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2541 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2542 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2544 IShellFolder_Release(psf);
2546 if(pSHGetPathFromIDListW){
2547 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2548 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2549 res = pSHGetPathFromIDListW(pidl, buf);
2550 ok(res == TRUE, "Got %d\n", res);
2551 if(SUCCEEDED(hrSI) && res)
2552 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2553 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2555 win_skip("pSHGetPathFromIDListW not available\n");
2557 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2558 todo_wine ok(hres == S_OK, "Got 0x%08x\n", hres);
2559 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2561 IShellItem_Release(shellitem);
2565 /* Test the control panel */
2566 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_CONTROLS, &pidl);
2567 ok(hres == S_OK, "Got 0x%08x\n", hres);
2568 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2569 ok(hres == S_OK, "Got 0x%08x\n", hres);
2572 WCHAR *nameSI, *nameSH;
2573 WCHAR buf[MAX_PATH];
2574 HRESULT hrSI, hrSH, hrSF;
2579 SHGetDesktopFolder(&psf);
2580 for(i = 0; flags[i] != -1234; i++)
2582 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2583 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2584 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2585 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2586 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2587 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2589 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2590 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2594 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2596 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2598 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2600 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2601 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2603 IShellFolder_Release(psf);
2605 if(pSHGetPathFromIDListW){
2606 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2607 ok(hrSI == E_INVALIDARG, "Got 0x%08x\n", hrSI);
2608 res = pSHGetPathFromIDListW(pidl, buf);
2609 ok(res == FALSE, "Got %d\n", res);
2610 if(SUCCEEDED(hrSI) && res)
2611 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2612 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2614 win_skip("pSHGetPathFromIDListW not available\n");
2616 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2617 todo_wine ok(hres == E_NOTIMPL /* Win7 */ || hres == S_OK /* Vista */,
2618 "Got 0x%08x\n", hres);
2619 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2621 IShellItem_Release(shellitem);
2626 static void test_SHGetItemFromDataObject(void)
2628 IShellFolder *psfdesktop;
2633 if(!pSHGetItemFromDataObject)
2635 win_skip("No SHGetItemFromDataObject.\n");
2641 /* Crashes under win7 */
2642 hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, NULL);
2645 hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, (void**)&psv);
2646 ok(hres == E_INVALIDARG, "got 0x%08x\n", hres);
2648 SHGetDesktopFolder(&psfdesktop);
2650 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
2651 ok(hres == S_OK, "got 0x%08x\n", hres);
2658 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
2659 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
2660 ok(hres == S_OK, "got 0x%08x\n", hres);
2663 LPITEMIDLIST apidl[5];
2666 for(count = 0; count < 5; count++)
2667 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
2672 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
2673 &IID_IDataObject, NULL, (void**)&pdo);
2674 ok(hres == S_OK, "got 0x%08x\n", hres);
2677 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2678 ok(hres == S_OK, "got 0x%08x\n", hres);
2679 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2680 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2681 ok(hres == S_OK, "got 0x%08x\n", hres);
2682 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2683 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2684 ok(hres == S_OK, "got 0x%08x\n", hres);
2685 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2686 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2687 ok(hres == S_OK, "got 0x%08x\n", hres);
2688 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2689 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2690 ok(hres == S_OK, "got 0x%08x\n", hres);
2691 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2693 IDataObject_Release(pdo);
2697 skip("No file(s) found - skipping single-file test.\n");
2701 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
2702 &IID_IDataObject, NULL, (void**)&pdo);
2703 ok(hres == S_OK, "got 0x%08x\n", hres);
2706 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2707 ok(hres == S_OK, "got 0x%08x\n", hres);
2708 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2709 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2710 ok(hres == S_OK, "got 0x%08x\n", hres);
2711 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2712 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2713 ok(hres == S_OK, "got 0x%08x\n", hres);
2714 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2715 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2716 ok(hres == S_OK, "got 0x%08x\n", hres);
2717 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2718 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2719 ok(hres == E_FAIL, "got 0x%08x\n", hres);
2720 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2721 IDataObject_Release(pdo);
2725 skip("zero or one file found - skipping multi-file test.\n");
2727 for(i = 0; i < count; i++)
2730 IEnumIDList_Release(peidl);
2733 IShellView_Release(psv);
2736 IShellFolder_Release(psfdesktop);
2739 static void test_ShellItemCompare(void)
2741 IShellItem *psi[9]; /* a\a, a\b, a\c, b\a, .. */
2742 IShellItem *psi_a = NULL, *psi_b = NULL, *psi_c = NULL;
2743 IShellFolder *psf_desktop, *psf_current;
2744 LPITEMIDLIST pidl_cwd;
2745 WCHAR curdirW[MAX_PATH];
2748 static const WCHAR filesW[][9] = {
2749 {'a','\\','a',0}, {'a','\\','b',0}, {'a','\\','c',0},
2750 {'b','\\','a',0}, {'b','\\','b',0}, {'b','\\','c',0},
2751 {'c','\\','a',0}, {'c','\\','b',0}, {'c','\\','c',0} };
2755 if(!pSHCreateShellItem)
2757 win_skip("SHCreateShellItem missing.\n");
2761 GetCurrentDirectoryW(MAX_PATH, curdirW);
2762 if(!lstrlenW(curdirW))
2764 skip("Failed to get current directory, skipping.\n");
2768 CreateDirectoryA(".\\a", NULL);
2769 CreateDirectoryA(".\\b", NULL);
2770 CreateDirectoryA(".\\c", NULL);
2771 CreateTestFile(".\\a\\a");
2772 CreateTestFile(".\\a\\b");
2773 CreateTestFile(".\\a\\c");
2774 CreateTestFile(".\\b\\a");
2775 CreateTestFile(".\\b\\b");
2776 CreateTestFile(".\\b\\c");
2777 CreateTestFile(".\\c\\a");
2778 CreateTestFile(".\\c\\b");
2779 CreateTestFile(".\\c\\c");
2781 SHGetDesktopFolder(&psf_desktop);
2782 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2783 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2784 hr = IShellFolder_BindToObject(psf_desktop, pidl_cwd, NULL, &IID_IShellFolder, (void**)&psf_current);
2785 ok(SUCCEEDED(hr), "BindToObject returned %x\n", hr);
2786 IShellFolder_Release(psf_desktop);
2789 /* Generate ShellItems for the files */
2790 memset(&psi, 0, sizeof(psi));
2792 for(i = 0; i < 9; i++)
2794 LPITEMIDLIST pidl_testfile = NULL;
2796 hr = IShellFolder_ParseDisplayName(psf_current, NULL, NULL, (LPWSTR)filesW[i],
2797 NULL, &pidl_testfile, NULL);
2798 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2801 hr = pSHCreateShellItem(NULL, NULL, pidl_testfile, &psi[i]);
2802 ok(hr == S_OK, "Got 0x%08x\n", hr);
2803 pILFree(pidl_testfile);
2805 if(FAILED(hr)) failed = TRUE;
2809 skip("Failed to create all shellitems.\n");
2813 /* Generate ShellItems for the folders */
2814 hr = IShellItem_GetParent(psi[0], &psi_a);
2815 ok(hr == S_OK, "Got 0x%08x\n", hr);
2816 if(FAILED(hr)) failed = TRUE;
2817 hr = IShellItem_GetParent(psi[3], &psi_b);
2818 ok(hr == S_OK, "Got 0x%08x\n", hr);
2819 if(FAILED(hr)) failed = TRUE;
2820 hr = IShellItem_GetParent(psi[6], &psi_c);
2821 ok(hr == S_OK, "Got 0x%08x\n", hr);
2822 if(FAILED(hr)) failed = TRUE;
2826 skip("Failed to create shellitems.\n");
2832 /* Crashes on native (win7, winxp) */
2833 hr = IShellItem_Compare(psi_a, NULL, 0, NULL);
2834 hr = IShellItem_Compare(psi_a, psi_b, 0, NULL);
2835 hr = IShellItem_Compare(psi_a, NULL, 0, &order);
2839 for(i = 0; i < 9; i++)
2841 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_DISPLAY, &order);
2842 ok(hr == S_OK, "Got 0x%08x\n", hr);
2843 ok(order == 0, "Got order %d\n", order);
2844 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_CANONICAL, &order);
2845 ok(hr == S_OK, "Got 0x%08x\n", hr);
2846 ok(order == 0, "Got order %d\n", order);
2847 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_ALLFIELDS, &order);
2848 ok(hr == S_OK, "Got 0x%08x\n", hr);
2849 ok(order == 0, "Got order %d\n", order);
2853 /* a\b:a\a , a\b:a\c, a\b:a\b */
2854 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_DISPLAY, &order);
2855 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2856 ok(order == 1, "Got order %d\n", order);
2857 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_DISPLAY, &order);
2858 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2859 ok(order == -1, "Got order %d\n", order);
2860 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_DISPLAY, &order);
2861 ok(hr == S_OK, "Got 0x%08x\n", hr);
2862 ok(order == 0, "Got order %d\n", order);
2864 /* b\b:a\b, b\b:c\b, b\b:c\b */
2865 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_DISPLAY, &order);
2866 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2867 ok(order == 1, "Got order %d\n", order);
2868 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_DISPLAY, &order);
2869 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2870 ok(order == -1, "Got order %d\n", order);
2871 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_DISPLAY, &order);
2872 ok(hr == S_OK, "Got 0x%08x\n", hr);
2873 ok(order == 0, "Got order %d\n", order);
2875 /* b:a\a, b:a\c, b:a\b */
2876 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_DISPLAY, &order);
2877 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2878 todo_wine ok(order == 1, "Got order %d\n", order);
2879 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_DISPLAY, &order);
2880 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2881 todo_wine ok(order == 1, "Got order %d\n", order);
2882 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_DISPLAY, &order);
2883 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2884 todo_wine ok(order == 1, "Got order %d\n", order);
2886 /* b:c\a, b:c\c, b:c\b */
2887 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_DISPLAY, &order);
2888 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2889 ok(order == -1, "Got order %d\n", order);
2890 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_DISPLAY, &order);
2891 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2892 ok(order == -1, "Got order %d\n", order);
2893 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_DISPLAY, &order);
2894 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2895 ok(order == -1, "Got order %d\n", order);
2897 /* a\b:a\a , a\b:a\c, a\b:a\b */
2898 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_CANONICAL, &order);
2899 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2900 ok(order == 1, "Got order %d\n", order);
2901 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_CANONICAL, &order);
2902 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2903 ok(order == -1, "Got order %d\n", order);
2904 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_CANONICAL, &order);
2905 ok(hr == S_OK, "Got 0x%08x\n", hr);
2906 ok(order == 0, "Got order %d\n", order);
2908 /* b\b:a\b, b\b:c\b, b\b:c\b */
2909 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_CANONICAL, &order);
2910 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2911 ok(order == 1, "Got order %d\n", order);
2912 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_CANONICAL, &order);
2913 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2914 ok(order == -1, "Got order %d\n", order);
2915 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_CANONICAL, &order);
2916 ok(hr == S_OK, "Got 0x%08x\n", hr);
2917 ok(order == 0, "Got order %d\n", order);
2919 /* b:a\a, b:a\c, b:a\b */
2920 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_CANONICAL, &order);
2921 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2922 todo_wine ok(order == 1, "Got order %d\n", order);
2923 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_CANONICAL, &order);
2924 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2925 todo_wine ok(order == 1, "Got order %d\n", order);
2926 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_CANONICAL, &order);
2927 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2928 todo_wine ok(order == 1, "Got order %d\n", order);
2930 /* b:c\a, b:c\c, b:c\b */
2931 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_CANONICAL, &order);
2932 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2933 ok(order == -1, "Got order %d\n", order);
2934 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_CANONICAL, &order);
2935 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2936 ok(order == -1, "Got order %d\n", order);
2937 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_CANONICAL, &order);
2938 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2939 ok(order == -1, "Got order %d\n", order);
2942 IShellFolder_Release(psf_current);
2944 DeleteFileA(".\\a\\a");
2945 DeleteFileA(".\\a\\b");
2946 DeleteFileA(".\\a\\c");
2947 DeleteFileA(".\\b\\a");
2948 DeleteFileA(".\\b\\b");
2949 DeleteFileA(".\\b\\c");
2950 DeleteFileA(".\\c\\a");
2951 DeleteFileA(".\\c\\b");
2952 DeleteFileA(".\\c\\c");
2953 RemoveDirectoryA(".\\a");
2954 RemoveDirectoryA(".\\b");
2955 RemoveDirectoryA(".\\c");
2957 if(psi_a) IShellItem_Release(psi_a);
2958 if(psi_b) IShellItem_Release(psi_b);
2959 if(psi_c) IShellItem_Release(psi_c);
2961 for(i = 0; i < 9; i++)
2962 if(psi[i]) IShellItem_Release(psi[i]);
2965 /**************************************************************/
2966 /* IUnknown implementation for counting QueryInterface calls. */
2968 const IUnknownVtbl *lpVtbl;
2976 static HRESULT WINAPI unk_fnQueryInterface(IUnknown *iunk, REFIID riid, void** punk)
2978 IUnknownImpl *This = (IUnknownImpl*)iunk;
2980 for(i = found = 0; This->ifaces[i].id != NULL; i++)
2982 if(IsEqualIID(This->ifaces[i].id, riid))
2984 This->ifaces[i].count++;
2991 return E_NOINTERFACE;
2994 static ULONG WINAPI unk_fnAddRef(IUnknown *iunk)
2999 static ULONG WINAPI unk_fnRelease(IUnknown *iunk)
3004 static const IUnknownVtbl vt_IUnknown = {
3005 unk_fnQueryInterface,
3010 static void test_SHGetIDListFromObject(void)
3012 IUnknownImpl *punkimpl;
3013 IShellFolder *psfdesktop;
3015 LPITEMIDLIST pidl, pidl_desktop;
3018 struct if_count ifaces[] =
3019 { {&IID_IPersistIDList, 0},
3020 {&IID_IPersistFolder2, 0},
3021 {&IID_IDataObject, 0},
3022 {&IID_IParentAndItem, 0},
3023 {&IID_IFolderView, 0},
3026 if(!pSHGetIDListFromObject)
3028 win_skip("SHGetIDListFromObject missing.\n");
3032 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
3036 /* Crashes native */
3037 pSHGetIDListFromObject(NULL, NULL);
3038 pSHGetIDListFromObject((void*)0xDEADBEEF, NULL);
3041 hres = pSHGetIDListFromObject(NULL, &pidl);
3042 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3044 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
3045 punkimpl->lpVtbl = &vt_IUnknown;
3046 punkimpl->ifaces = ifaces;
3047 punkimpl->unknown = 0;
3049 hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
3050 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3051 ok(ifaces[0].count, "interface not requested.\n");
3052 ok(ifaces[1].count, "interface not requested.\n");
3053 ok(ifaces[2].count, "interface not requested.\n");
3055 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3056 "interface not requested.\n");
3057 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3058 "interface not requested.\n");
3060 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3061 HeapFree(GetProcessHeap(), 0, punkimpl);
3063 pidl_desktop = NULL;
3064 pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3065 ok(pidl_desktop != NULL, "Failed to get desktop pidl.\n");
3067 SHGetDesktopFolder(&psfdesktop);
3069 /* Test IShellItem */
3070 if(pSHCreateShellItem)
3072 IShellItem *shellitem;
3073 hres = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
3074 ok(hres == S_OK, "got 0x%08x\n", hres);
3077 hres = pSHGetIDListFromObject((IUnknown*)shellitem, &pidl);
3078 ok(hres == S_OK, "got 0x%08x\n", hres);
3081 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3084 IShellItem_Release(shellitem);
3088 skip("no SHCreateShellItem.\n");
3090 /* Test IShellFolder */
3091 hres = pSHGetIDListFromObject((IUnknown*)psfdesktop, &pidl);
3092 ok(hres == S_OK, "got 0x%08x\n", hres);
3095 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3099 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
3100 ok(hres == S_OK, "got 0x%08x\n", hres);
3107 /* Test IFolderView */
3108 hres = pSHGetIDListFromObject((IUnknown*)psv, &pidl);
3109 ok(hres == S_OK, "got 0x%08x\n", hres);
3112 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3116 /* Test IDataObject */
3117 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3118 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
3119 ok(hres == S_OK, "got 0x%08x\n", hres);
3122 LPITEMIDLIST apidl[5];
3124 for(count = 0; count < 5; count++)
3125 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3130 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
3131 &IID_IDataObject, NULL, (void**)&pdo);
3132 ok(hres == S_OK, "got 0x%08x\n", hres);
3135 pidl = (void*)0xDEADBEEF;
3136 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3137 ok(hres == S_OK, "got 0x%08x\n", hres);
3138 ok(pidl != NULL, "pidl is NULL.\n");
3139 ok(ILIsEqual(pidl, apidl[0]), "pidl not equal.\n");
3142 IDataObject_Release(pdo);
3146 skip("No files found - skipping single-file test.\n");
3150 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
3151 &IID_IDataObject, NULL, (void**)&pdo);
3152 ok(hres == S_OK, "got 0x%08x\n", hres);
3155 pidl = (void*)0xDEADBEEF;
3156 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3157 ok(hres == E_NOINTERFACE || hres == E_FAIL /*Vista*/,
3158 "got 0x%08x\n", hres);
3159 ok(pidl == NULL, "pidl is not NULL.\n");
3161 IDataObject_Release(pdo);
3165 skip("zero or one file found - skipping multi-file test.\n");
3167 for(i = 0; i < count; i++)
3170 IEnumIDList_Release(peidl);
3173 IShellView_Release(psv);
3176 IShellFolder_Release(psfdesktop);
3177 pILFree(pidl_desktop);
3180 static void test_SHGetItemFromObject(void)
3182 IUnknownImpl *punkimpl;
3183 IShellFolder *psfdesktop;
3188 struct if_count ifaces[] =
3189 { {&IID_IPersistIDList, 0},
3190 {&IID_IPersistFolder2, 0},
3191 {&IID_IDataObject, 0},
3192 {&IID_IParentAndItem, 0},
3193 {&IID_IFolderView, 0},
3196 if(!pSHGetItemFromObject)
3198 skip("No SHGetItemFromObject.\n");
3202 SHGetDesktopFolder(&psfdesktop);
3206 /* Crashes with Windows 7 */
3207 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IUnknown, NULL);
3208 hres = pSHGetItemFromObject(NULL, &IID_IUnknown, NULL);
3209 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, NULL, (void**)&punk);
3212 hres = pSHGetItemFromObject(NULL, &IID_IUnknown, (void**)&punk);
3213 ok(hres == E_NOINTERFACE, "Got 0x%08x\n", hres);
3215 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
3216 punkimpl->lpVtbl = &vt_IUnknown;
3217 punkimpl->ifaces = ifaces;
3218 punkimpl->unknown = 0;
3220 /* The same as SHGetIDListFromObject */
3221 hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
3222 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3223 ok(ifaces[0].count, "interface not requested.\n");
3224 ok(ifaces[1].count, "interface not requested.\n");
3225 ok(ifaces[2].count, "interface not requested.\n");
3227 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3228 "interface not requested.\n");
3229 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3230 "interface not requested.\n");
3232 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3233 HeapFree(GetProcessHeap(), 0, punkimpl);
3235 /* Test IShellItem */
3236 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IShellItem, (void**)&psi);
3237 ok(hres == S_OK, "Got 0x%08x\n", hres);
3241 hres = pSHGetItemFromObject((IUnknown*)psi, &IID_IShellItem, (void**)&psi2);
3242 ok(hres == S_OK, "Got 0x%08x\n", hres);
3246 ok(psi == psi2, "Different instances (%p != %p).\n", psi, psi2);
3247 IShellItem_Release(psi2);
3249 IShellItem_Release(psi);
3252 IShellFolder_Release(psfdesktop);
3255 static void test_SHCreateShellItemArray(void)
3257 IShellFolder *pdesktopsf, *psf;
3258 IShellItemArray *psia;
3261 WCHAR cTestDirW[MAX_PATH];
3262 LPITEMIDLIST pidl_testdir, pidl;
3263 static const WCHAR testdirW[] = {'t','e','s','t','d','i','r',0};
3265 if(!pSHCreateShellItemArray) {
3266 skip("No pSHCreateShellItemArray!\n");
3270 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
3274 /* Crashes under native */
3275 pSHCreateShellItemArray(NULL, NULL, 0, NULL, NULL);
3276 pSHCreateShellItemArray(NULL, NULL, 1, NULL, NULL);
3277 pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, NULL);
3278 pSHCreateShellItemArray(pidl, NULL, 0, NULL, NULL);
3281 hr = pSHCreateShellItemArray(NULL, NULL, 0, NULL, &psia);
3282 ok(hr == E_POINTER, "got 0x%08x\n", hr);
3284 SHGetDesktopFolder(&pdesktopsf);
3285 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, &psia);
3286 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3288 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 1, NULL, &psia);
3289 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3291 pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
3292 hr = pSHCreateShellItemArray(pidl, NULL, 0, NULL, &psia);
3293 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3296 GetCurrentDirectoryW(MAX_PATH, cTestDirW);
3297 myPathAddBackslashW(cTestDirW);
3298 lstrcatW(cTestDirW, testdirW);
3300 CreateFilesFolders();
3302 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, cTestDirW, NULL, &pidl_testdir, 0);
3303 ok(hr == S_OK, "got 0x%08x\n", hr);
3306 hr = IShellFolder_BindToObject(pdesktopsf, pidl_testdir, NULL, (REFIID)&IID_IShellFolder,
3308 ok(hr == S_OK, "Got 0x%08x\n", hr);
3310 IShellFolder_Release(pdesktopsf);
3314 skip("Failed to set up environment for SHCreateShellItemArray tests.\n");
3315 pILFree(pidl_testdir);
3320 hr = IShellFolder_EnumObjects(psf, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &peidl);
3321 ok(hr == S_OK, "Got %08x\n", hr);
3324 LPITEMIDLIST apidl[5];
3325 UINT done, numitems, i;
3327 for(done = 0; done < 5; done++)
3328 if(IEnumIDList_Next(peidl, 1, &apidl[done], NULL) != S_OK)
3330 ok(done == 5, "Got %d pidls\n", done);
3331 IEnumIDList_Release(peidl);
3333 /* Create a ShellItemArray */
3334 hr = pSHCreateShellItemArray(NULL, psf, done, (LPCITEMIDLIST*)apidl, &psia);
3335 ok(hr == S_OK, "Got 0x%08x\n", hr);
3342 /* Crashes in Windows 7 */
3343 hr = IShellItemArray_GetCount(psia, NULL);
3346 IShellItemArray_GetCount(psia, &numitems);
3347 ok(numitems == done, "Got %d, expected %d\n", numitems, done);
3349 hr = IShellItemArray_GetItemAt(psia, numitems, &psi);
3350 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3352 /* Compare all the items */
3353 for(i = 0; i < numitems; i++)
3355 LPITEMIDLIST pidl_abs;
3356 pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3358 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3359 ok(hr == S_OK, "(%d) Failed with 0x%08x\n", i, hr);
3362 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3363 ok(hr == S_OK, "Got 0x%08x\n", hr);
3366 ok(ILIsEqual(pidl_abs, pidl), "Pidl not equal.\n");
3369 IShellItem_Release(psi);
3373 for(i = 0; i < done; i++)
3375 IShellItemArray_Release(psia);
3379 /* SHCreateShellItemArrayFromShellItem */
3380 if(pSHCreateShellItemArrayFromShellItem)
3386 /* Crashes under Windows 7 */
3387 hr = pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, NULL);
3388 hr = pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, (void**)&psia);
3389 hr = pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, NULL);
3392 hr = pSHCreateItemFromIDList(pidl_testdir, &IID_IShellItem, (void**)&psi);
3393 ok(hr == S_OK, "Got 0x%08x\n", hr);
3396 hr = pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, (void**)&psia);
3397 ok(hr == S_OK, "Got 0x%08x\n", hr);
3402 hr = IShellItemArray_GetCount(psia, &count);
3403 ok(hr == S_OK, "Got 0x%08x\n", hr);
3404 ok(count == 1, "Got count %d\n", count);
3405 hr = IShellItemArray_GetItemAt(psia, 0, &psi2);
3406 ok(hr == S_OK, "Got 0x%08x\n", hr);
3408 ok(psi != psi2, "ShellItems are of the same instance.\n");
3411 LPITEMIDLIST pidl1, pidl2;
3412 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl1);
3413 ok(hr == S_OK, "Got 0x%08x\n", hr);
3414 ok(pidl1 != NULL, "pidl1 was null.\n");
3415 hr = pSHGetIDListFromObject((IUnknown*)psi2, &pidl2);
3416 ok(hr == S_OK, "Got 0x%08x\n", hr);
3417 ok(pidl2 != NULL, "pidl2 was null.\n");
3418 ok(ILIsEqual(pidl1, pidl2), "pidls not equal.\n");
3421 IShellItem_Release(psi2);
3423 hr = IShellItemArray_GetItemAt(psia, 1, &psi2);
3424 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3425 IShellItemArray_Release(psia);
3427 IShellItem_Release(psi);
3431 skip("No SHCreateShellItemArrayFromShellItem.\n");
3433 if(pSHCreateShellItemArrayFromDataObject)
3439 /* Crashes under Windows 7 */
3440 hr = pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, NULL);
3442 hr = pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, (void**)&psia);
3443 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3445 hr = IShellFolder_CreateViewObject(psf, NULL, &IID_IShellView, (void**)&psv);
3446 ok(hr == S_OK, "got 0x%08x\n", hr);
3453 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3454 hr = IShellFolder_EnumObjects(psf, NULL, enum_flags, &peidl);
3455 ok(hr == S_OK, "got 0x%08x\n", hr);
3458 LPITEMIDLIST apidl[5];
3461 for(count = 0; count < 5; count++)
3462 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3464 ok(count == 5, "Got %d\n", count);
3468 hr = IShellFolder_GetUIObjectOf(psf, NULL, count, (LPCITEMIDLIST*)apidl,
3469 &IID_IDataObject, NULL, (void**)&pdo);
3470 ok(hr == S_OK, "Got 0x%08x\n", hr);
3473 hr = pSHCreateShellItemArrayFromDataObject(pdo, &IID_IShellItemArray,
3475 ok(hr == S_OK, "Got 0x%08x\n", hr);
3479 hr = IShellItemArray_GetCount(psia, &count_sia);
3480 ok(count_sia == count, "Counts differ (%d, %d)\n", count, count_sia);
3481 for(i = 0; i < count_sia; i++)
3483 LPITEMIDLIST pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3485 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3486 ok(hr == S_OK, "Got 0x%08x\n", hr);
3490 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3491 ok(hr == S_OK, "Got 0x%08x\n", hr);
3492 ok(pidl != NULL, "pidl as NULL.\n");
3493 ok(ILIsEqual(pidl, pidl_abs), "pidls differ.\n");
3495 IShellItem_Release(psi);
3500 IShellItemArray_Release(psia);
3503 IDataObject_Release(pdo);
3505 for(i = 0; i < count; i++)
3509 skip("No files found - skipping test.\n");
3511 IEnumIDList_Release(peidl);
3513 IShellView_Release(psv);
3517 skip("No SHCreateShellItemArrayFromDataObject.\n");
3519 IShellFolder_Release(psf);
3520 pILFree(pidl_testdir);
3524 static void test_ShellItemBindToHandler(void)
3527 LPITEMIDLIST pidl_desktop;
3530 if(!pSHCreateShellItem)
3532 skip("SHCreateShellItem missing.\n");
3536 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3537 ok(hr == S_OK, "Got 0x%08x\n", hr);
3540 hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
3541 ok(hr == S_OK, "Got 0x%08x\n", hr);
3545 IPersistFolder2 *ppf2;
3550 /* Crashes under Windows 7 */
3551 hr = IShellItem_BindToHandler(psi, NULL, NULL, NULL, NULL);
3552 hr = IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, NULL);
3554 hr = IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, (void**)&punk);
3555 ok(hr == MK_E_NOOBJECT, "Got 0x%08x\n", hr);
3558 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IShellFolder, (void**)&punk);
3559 ok(hr == S_OK, "Got 0x%08x\n", hr);
3560 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3561 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IPersistFolder2, (void**)&ppf2);
3562 ok(hr == S_OK, "Got 0x%08x\n", hr);
3565 LPITEMIDLIST pidl_tmp;
3566 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl_tmp);
3567 ok(hr == S_OK, "Got 0x%08x\n", hr);
3570 ok(ILIsEqual(pidl_desktop, pidl_tmp), "Pidl not equal (%p, %p)\n", pidl_desktop, pidl_tmp);
3573 IPersistFolder2_Release(ppf2);
3576 /* BHID_SFUIObject */
3577 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IDataObject, (void**)&punk);
3578 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3579 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3580 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IContextMenu, (void**)&punk);
3581 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3582 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3584 /* BHID_DataObject */
3585 hr = IShellItem_BindToHandler(psi, NULL, &BHID_DataObject, &IID_IDataObject, (void**)&punk);
3586 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3587 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3591 /* BHID_SFViewObject */
3592 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellView, (void**)&punk);
3593 ok(hr == S_OK, "Got 0x%08x\n", hr);
3594 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3595 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellFolderView, (void**)&punk);
3596 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3597 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3600 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IStream, (void**)&punk);
3601 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3602 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3603 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IUnknown, (void**)&punk);
3604 ok(hr == S_OK, "Got 0x%08x\n", hr);
3605 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3608 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IStream, (void**)&punk);
3609 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3610 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3611 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IUnknown, (void**)&punk);
3612 ok(hr == S_OK, "Got 0x%08x\n", hr);
3613 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3615 /* BHID_StorageEnum */
3616 hr = IShellItem_BindToHandler(psi, NULL, &BHID_StorageEnum, &IID_IEnumShellItems, (void**)&punk);
3617 ok(hr == S_OK, "Got 0x%08x\n", hr);
3618 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3621 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_IUnknown, (void**)&punk);
3622 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3623 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3625 /* BHID_EnumItems */
3626 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumItems, &IID_IEnumShellItems, (void**)&punk);
3627 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3628 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3631 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Filter, &IID_IUnknown, (void**)&punk);
3632 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3633 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3635 /* BHID_LinkTargetItem */
3636 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IShellItem, (void**)&punk);
3637 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3638 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3639 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IUnknown, (void**)&punk);
3640 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3641 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3643 /* BHID_PropertyStore */
3644 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStore, (void**)&punk);
3645 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3646 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3647 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStoreFactory, (void**)&punk);
3648 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3649 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3651 /* BHID_ThumbnailHandler */
3652 hr = IShellItem_BindToHandler(psi, NULL, &BHID_ThumbnailHandler, &IID_IUnknown, (void**)&punk);
3653 ok(hr == E_INVALIDARG || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3654 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3656 /* BHID_AssociationArray */
3657 hr = IShellItem_BindToHandler(psi, NULL, &BHID_AssociationArray, &IID_IQueryAssociations, (void**)&punk);
3658 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3659 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3661 /* BHID_EnumAssocHandlers */
3662 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumAssocHandlers, &IID_IUnknown, (void**)&punk);
3663 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3664 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3667 IShellItem_Release(psi);
3670 skip("Failed to create ShellItem.\n");
3672 pILFree(pidl_desktop);
3675 void test_ShellItemGetAttributes(void)
3678 LPITEMIDLIST pidl_desktop;
3682 if(!pSHCreateShellItem)
3684 skip("SHCreateShellItem missing.\n");
3688 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3689 ok(hr == S_OK, "Got 0x%08x\n", hr);
3692 hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
3693 ok(hr == S_OK, "Got 0x%08x\n", hr);
3694 pILFree(pidl_desktop);
3698 skip("Skipping tests.");
3704 /* Crashes on native (Win 7) */
3705 hr = IShellItem_GetAttributes(psi, 0, NULL);
3706 ok(hr == S_OK, "Got 0x%08x\n", hr);
3709 /* Test GetAttributes on the desktop folder. */
3711 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER, &sfgao);
3712 ok(hr == S_OK || broken(hr == E_FAIL) /* <Vista */, "Got 0x%08x\n", hr);
3713 ok(sfgao == SFGAO_FOLDER || broken(sfgao == 0) /* <Vista */, "Got 0x%08x\n", sfgao);
3715 IShellItem_Release(psi);
3718 static void test_SHParseDisplayName(void)
3720 LPITEMIDLIST pidl1, pidl2;
3721 IShellFolder *desktop;
3722 WCHAR dirW[MAX_PATH];
3727 if (!pSHParseDisplayName)
3729 win_skip("SHParseDisplayName isn't available\n");
3735 /* crashes on native */
3736 hr = pSHParseDisplayName(NULL, NULL, NULL, 0, NULL);
3738 hr = pSHParseDisplayName(nameW, NULL, NULL, 0, NULL);
3741 pidl1 = (LPITEMIDLIST)0xdeadbeef;
3742 hr = pSHParseDisplayName(NULL, NULL, &pidl1, 0, NULL);
3743 ok(broken(hr == E_OUTOFMEMORY) /* < Vista */ ||
3744 hr == E_INVALIDARG, "failed %08x\n", hr);
3745 ok(pidl1 == 0, "expected null ptr, got %p\n", pidl1);
3749 hr = pSHParseDisplayName(nameW, NULL, &pidl1, 0, NULL);
3750 ok(hr == S_OK, "failed %08x\n", hr);
3751 hr = SHGetDesktopFolder(&desktop);
3752 ok(hr == S_OK, "failed %08x\n", hr);
3753 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, nameW, NULL, &pidl2, NULL);
3754 ok(hr == S_OK, "failed %08x\n", hr);
3755 ret = pILIsEqual(pidl1, pidl2);
3756 ok(ret == TRUE, "expected equal idls\n");
3761 GetWindowsDirectoryW( dirW, MAX_PATH );
3763 hr = pSHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
3764 ok(hr == S_OK, "failed %08x\n", hr);
3765 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, dirW, NULL, &pidl2, NULL);
3766 ok(hr == S_OK, "failed %08x\n", hr);
3768 ret = pILIsEqual(pidl1, pidl2);
3769 ok(ret == TRUE, "expected equal idls\n");
3773 IShellFolder_Release(desktop);
3776 static void test_desktop_IPersist(void)
3778 IShellFolder *desktop;
3780 IPersistFolder2 *ppf2;
3784 hr = SHGetDesktopFolder(&desktop);
3785 ok(hr == S_OK, "failed %08x\n", hr);
3787 hr = IShellFolder_QueryInterface(desktop, &IID_IPersist, (void**)&persist);
3788 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* NT4, W9X */, "failed %08x\n", hr);
3794 /* crashes on native */
3795 hr = IPersist_GetClassID(persist, NULL);
3797 memset(&clsid, 0, sizeof(clsid));
3798 hr = IPersist_GetClassID(persist, &clsid);
3799 ok(hr == S_OK, "failed %08x\n", hr);
3800 ok(IsEqualIID(&CLSID_ShellDesktop, &clsid), "Expected CLSID_ShellDesktop\n");
3801 IPersist_Release(persist);
3804 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder2, (void**)&ppf2);
3805 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* pre-Vista */, "failed %08x\n", hr);
3808 IPersistFolder *ppf;
3810 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder, (void**)&ppf);
3811 ok(hr == S_OK, "IID_IPersistFolder2 without IID_IPersistFolder.\n");
3813 IPersistFolder_Release(ppf);
3816 hr = IPersistFolder2_Initialize(ppf2, NULL);
3817 ok(hr == S_OK, "got %08x\n", hr);
3821 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl);
3822 ok(hr == S_OK, "got %08x\n", hr);
3823 ok(pidl != NULL, "pidl was NULL.\n");
3824 if(SUCCEEDED(hr)) pILFree(pidl);
3826 IPersistFolder2_Release(ppf2);
3829 IShellFolder_Release(desktop);
3832 static void test_GetUIObject(void)
3834 IShellFolder *psf_desktop;
3838 WCHAR path[MAX_PATH];
3839 const WCHAR filename[] =
3840 {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
3842 if(!pSHBindToParent)
3844 win_skip("SHBindToParent missing.\n");
3848 GetCurrentDirectoryW(MAX_PATH, path);
3851 skip("GetCurrentDirectoryW returned an empty string.\n");
3854 lstrcatW(path, filename);
3855 SHGetDesktopFolder(&psf_desktop);
3857 CreateFilesFolders();
3859 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, path, NULL, &pidl, 0);
3860 ok(hr == S_OK || broken(hr == E_FAIL) /* WinME */, "Got 0x%08x\n", hr);
3864 LPCITEMIDLIST pidl_child;
3865 hr = pSHBindToParent(pidl, &IID_IShellFolder, (void**)&psf, &pidl_child);
3866 ok(hr == S_OK, "Got 0x%08x\n", hr);
3869 hr = IShellFolder_GetUIObjectOf(psf, NULL, 1, (LPCITEMIDLIST*)&pidl_child,
3870 &IID_IContextMenu, NULL, (void**)&pcm);
3871 ok(hr == S_OK, "Got 0x%08x\n", hr);
3874 HMENU hmenu = CreatePopupMenu();
3875 INT max_id, max_id_check;
3877 const int id_upper_limit = 32767;
3878 hr = IContextMenu_QueryContextMenu(pcm, hmenu, 0, 0, id_upper_limit, CMF_NORMAL);
3879 ok(SUCCEEDED(hr), "Got 0x%08x\n", hr);
3880 max_id = HRESULT_CODE(hr) - 1; /* returns max_id + 1 */
3881 ok(max_id <= id_upper_limit, "Got %d\n", max_id);
3882 count = GetMenuItemCount(hmenu);
3883 ok(count, "Got %d\n", count);
3886 for(i = 0; i < count; i++)
3890 ZeroMemory(&mii, sizeof(MENUITEMINFOA));
3891 mii.cbSize = sizeof(MENUITEMINFOA);
3892 mii.fMask = MIIM_ID | MIIM_FTYPE;
3895 res = GetMenuItemInfoA(hmenu, i, TRUE, &mii);
3896 ok(res, "Failed (last error: %d).\n", GetLastError());
3898 ok( (mii.wID <= id_upper_limit) || (mii.fType & MFT_SEPARATOR),
3899 "Got non-separator ID out of range: %d (type: %x)\n", mii.wID, mii.fType);
3900 if(!(mii.fType & MFT_SEPARATOR))
3901 max_id_check = (mii.wID>max_id_check)?mii.wID:max_id_check;
3903 ok((max_id_check == max_id) ||
3904 (max_id_check == max_id-1 /* Win 7 */),
3905 "Not equal (or near equal), got %d and %d\n", max_id_check, max_id);
3907 #define is_win2k() (pSHGetFolderPathA && !pSHGetFolderPathAndSubDirA)
3909 if(count && !is_win2k()) /* Test is interactive on w2k, so skip */
3911 CMINVOKECOMMANDINFO cmi;
3912 ZeroMemory(&cmi, sizeof(CMINVOKECOMMANDINFO));
3913 cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
3915 /* Attempt to execute a nonexistent command */
3916 cmi.lpVerb = MAKEINTRESOURCEA(9999);
3917 hr = IContextMenu_InvokeCommand(pcm, &cmi);
3918 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3920 cmi.lpVerb = "foobar_wine_test";
3921 hr = IContextMenu_InvokeCommand(pcm, &cmi);
3922 ok( (hr == E_INVALIDARG) || (hr == E_FAIL /* Win7 */) ||
3923 (hr == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION) /* Vista */),
3924 "Got 0x%08x\n", hr);
3929 IContextMenu_Release(pcm);
3931 IShellFolder_Release(psf);
3933 if(pILFree) pILFree(pidl);
3936 IShellFolder_Release(psf_desktop);
3940 #define verify_pidl(i,p) r_verify_pidl(__LINE__, i, p)
3941 static void r_verify_pidl(unsigned l, LPCITEMIDLIST pidl, const WCHAR *path)
3943 LPCITEMIDLIST child;
3944 IShellFolder *parent;
3948 if(!pSHBindToParent){
3949 win_skip("SHBindToParent is not available, not performing full PIDL verification\n");
3951 ok_(__FILE__,l)(pidl != NULL, "Expected PIDL to be non-NULL\n");
3953 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
3959 ok_(__FILE__,l)(0, "didn't get expected path (%s), instead: NULL\n", wine_dbgstr_w(path));
3963 hr = pSHBindToParent(pidl, &IID_IShellFolder, (LPVOID*)&parent, &child);
3964 ok_(__FILE__,l)(hr == S_OK, "SHBindToParent failed: 0x%08x\n", hr);
3968 hr = IShellFolder_GetDisplayNameOf(parent, child, SHGDN_FORPARSING, &filename);
3969 ok_(__FILE__,l)(hr == S_OK, "GetDisplayNameOf failed: 0x%08x\n", hr);
3971 IShellFolder_Release(parent);
3975 ok_(__FILE__,l)(filename.uType == STRRET_WSTR || filename.uType == STRRET_CSTR,
3976 "Got unexpected string type: %d\n", filename.uType);
3977 if(filename.uType == STRRET_WSTR){
3978 ok_(__FILE__,l)(lstrcmpW(path, U(filename).pOleStr) == 0,
3979 "didn't get expected path (%s), instead: %s\n",
3980 wine_dbgstr_w(path), wine_dbgstr_w(U(filename).pOleStr));
3981 SHFree(U(filename).pOleStr);
3982 }else if(filename.uType == STRRET_CSTR){
3983 ok_(__FILE__,l)(strcmp_wa(path, U(filename).cStr) == 0,
3984 "didn't get expected path (%s), instead: %s\n",
3985 wine_dbgstr_w(path), U(filename).cStr);
3988 IShellFolder_Release(parent);
3990 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
3993 static void test_SHSimpleIDListFromPath(void)
3995 const WCHAR adirW[] = {'C',':','\\','s','i','d','l','f','p','d','i','r',0};
3996 const CHAR adirA[] = "C:\\sidlfpdir";
3997 BOOL br, is_unicode = !(GetVersion() & 0x80000000);
3999 LPITEMIDLIST pidl = NULL;
4001 if(!pSHSimpleIDListFromPathAW){
4002 win_skip("SHSimpleIDListFromPathAW not available\n");
4006 br = CreateDirectoryA(adirA, NULL);
4007 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
4010 pidl = pSHSimpleIDListFromPathAW(adirW);
4012 pidl = pSHSimpleIDListFromPathAW(adirA);
4013 verify_pidl(pidl, adirW);
4016 br = RemoveDirectoryA(adirA);
4017 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4020 pidl = pSHSimpleIDListFromPathAW(adirW);
4022 pidl = pSHSimpleIDListFromPathAW(adirA);
4023 verify_pidl(pidl, adirW);
4027 /* IFileSystemBindData impl */
4028 static HRESULT WINAPI fsbd_QueryInterface(IFileSystemBindData *fsbd,
4029 REFIID riid, void **ppv)
4031 if(IsEqualIID(riid, &IID_IFileSystemBindData) ||
4032 IsEqualIID(riid, &IID_IUnknown)){
4036 return E_NOINTERFACE;
4039 static ULONG WINAPI fsbd_AddRef(IFileSystemBindData *fsbd)
4044 static ULONG WINAPI fsbd_Release(IFileSystemBindData *fsbd)
4049 static HRESULT WINAPI fsbd_SetFindData(IFileSystemBindData *fsbd,
4050 const WIN32_FIND_DATAW *pfd)
4052 ok(0, "SetFindData called\n");
4056 static HRESULT WINAPI fsbd_GetFindData_nul(IFileSystemBindData *fsbd,
4057 WIN32_FIND_DATAW *pfd)
4059 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
4063 static HRESULT WINAPI fsbd_GetFindData_junk(IFileSystemBindData *fsbd,
4064 WIN32_FIND_DATAW *pfd)
4066 memset(pfd, 0xdeadbeef, sizeof(WIN32_FIND_DATAW));
4070 static HRESULT WINAPI fsbd_GetFindData_invalid(IFileSystemBindData *fsbd,
4071 WIN32_FIND_DATAW *pfd)
4073 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
4074 *pfd->cFileName = 'a';
4075 *pfd->cAlternateFileName = 'a';
4079 static HRESULT WINAPI fsbd_GetFindData_valid(IFileSystemBindData *fsbd,
4080 WIN32_FIND_DATAW *pfd)
4082 static const WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4083 HANDLE handle = FindFirstFileW(adirW, pfd);
4088 static HRESULT WINAPI fsbd_GetFindData_fail(IFileSystemBindData *fsbd,
4089 WIN32_FIND_DATAW *pfd)
4094 static IFileSystemBindDataVtbl fsbdVtbl = {
4095 fsbd_QueryInterface,
4102 static IFileSystemBindData fsbd = { &fsbdVtbl };
4104 static void test_ParseDisplayNamePBC(void)
4106 WCHAR wFileSystemBindData[] =
4107 {'F','i','l','e',' ','S','y','s','t','e','m',' ','B','i','n','d',' ','D','a','t','a',0};
4108 WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4109 WCHAR afileW[] = {'C',':','\\','f','s','b','d','d','i','r','\\','f','i','l','e','.','t','x','t',0};
4110 WCHAR afile2W[] = {'C',':','\\','f','s','b','d','d','i','r','\\','s','\\','f','i','l','e','.','t','x','t',0};
4111 const HRESULT exp_err = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
4118 /* Check if we support WCHAR functions */
4119 SetLastError(0xdeadbeef);
4120 lstrcmpiW(adirW, adirW);
4121 if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED){
4122 win_skip("Most W-calls are not implemented\n");
4126 hres = SHGetDesktopFolder(&psf);
4127 ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
4129 win_skip("Failed to get IShellFolder, can't run tests\n");
4133 /* fails on unknown dir with no IBindCtx */
4134 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, adirW, NULL, &pidl, NULL);
4135 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4136 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4137 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, afileW, NULL, &pidl, NULL);
4138 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4139 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4140 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, afile2W, NULL, &pidl, NULL);
4141 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4142 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4144 /* fails on unknown dir with IBindCtx with no IFileSystemBindData */
4145 hres = CreateBindCtx(0, &pbc);
4146 ok(hres == S_OK, "CreateBindCtx failed: 0x%08x\n", hres);
4148 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4149 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4150 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4151 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4152 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4153 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4154 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4155 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4156 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4158 /* unknown dir with IBindCtx with IFileSystemBindData */
4159 hres = IBindCtx_RegisterObjectParam(pbc, wFileSystemBindData, (IUnknown*)&fsbd);
4160 ok(hres == S_OK, "RegisterObjectParam failed: 0x%08x\n", hres);
4162 /* return E_FAIL from GetFindData */
4163 pidl = (ITEMIDLIST*)0xdeadbeef;
4164 fsbdVtbl.GetFindData = fsbd_GetFindData_fail;
4165 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4166 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4167 "ParseDisplayName failed: 0x%08x\n", hres);
4168 if(SUCCEEDED(hres)){
4169 verify_pidl(pidl, adirW);
4173 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4174 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4175 "ParseDisplayName failed: 0x%08x\n", hres);
4176 if(SUCCEEDED(hres)){
4177 verify_pidl(pidl, afileW);
4181 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4182 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4183 "ParseDisplayName failed: 0x%08x\n", hres);
4184 if(SUCCEEDED(hres)){
4185 verify_pidl(pidl, afile2W);
4189 /* set FIND_DATA struct to NULLs */
4190 pidl = (ITEMIDLIST*)0xdeadbeef;
4191 fsbdVtbl.GetFindData = fsbd_GetFindData_nul;
4192 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4193 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4194 "ParseDisplayName failed: 0x%08x\n", hres);
4195 if(SUCCEEDED(hres)){
4196 verify_pidl(pidl, adirW);
4200 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4201 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4202 "ParseDisplayName failed: 0x%08x\n", hres);
4203 if(SUCCEEDED(hres)){
4204 verify_pidl(pidl, afileW);
4208 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4209 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4210 "ParseDisplayName failed: 0x%08x\n", hres);
4211 if(SUCCEEDED(hres)){
4212 verify_pidl(pidl, afile2W);
4216 /* set FIND_DATA struct to junk */
4217 pidl = (ITEMIDLIST*)0xdeadbeef;
4218 fsbdVtbl.GetFindData = fsbd_GetFindData_junk;
4219 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4220 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4221 "ParseDisplayName failed: 0x%08x\n", hres);
4222 if(SUCCEEDED(hres)){
4223 verify_pidl(pidl, adirW);
4227 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4228 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4229 "ParseDisplayName failed: 0x%08x\n", hres);
4230 if(SUCCEEDED(hres)){
4231 verify_pidl(pidl, afileW);
4235 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4236 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4237 "ParseDisplayName failed: 0x%08x\n", hres);
4238 if(SUCCEEDED(hres)){
4239 verify_pidl(pidl, afile2W);
4243 /* set FIND_DATA struct to invalid data */
4244 pidl = (ITEMIDLIST*)0xdeadbeef;
4245 fsbdVtbl.GetFindData = fsbd_GetFindData_invalid;
4246 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4247 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4248 "ParseDisplayName failed: 0x%08x\n", hres);
4249 if(SUCCEEDED(hres)){
4250 verify_pidl(pidl, adirW);
4254 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4255 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4256 "ParseDisplayName failed: 0x%08x\n", hres);
4257 if(SUCCEEDED(hres)){
4258 verify_pidl(pidl, afileW);
4262 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4263 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4264 "ParseDisplayName failed: 0x%08x\n", hres);
4265 if(SUCCEEDED(hres)){
4266 verify_pidl(pidl, afile2W);
4270 /* set FIND_DATA struct to valid data */
4271 pidl = (ITEMIDLIST*)0xdeadbeef;
4272 fsbdVtbl.GetFindData = fsbd_GetFindData_valid;
4273 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4274 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4275 "ParseDisplayName failed: 0x%08x\n", hres);
4276 if(SUCCEEDED(hres)){
4277 verify_pidl(pidl, adirW);
4281 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4282 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4283 "ParseDisplayName failed: 0x%08x\n", hres);
4284 if(SUCCEEDED(hres)){
4285 verify_pidl(pidl, afileW);
4289 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4290 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4291 "ParseDisplayName failed: 0x%08x\n", hres);
4292 if(SUCCEEDED(hres)){
4293 verify_pidl(pidl, afile2W);
4297 IBindCtx_Release(pbc);
4298 IShellFolder_Release(psf);
4301 static const CHAR testwindow_class[] = "testwindow";
4302 #define WM_USER_NOTIFY (WM_APP+1)
4304 struct ChNotifyTest {
4306 const UINT notify_count;
4307 UINT missing_events;
4309 const char path_1[256];
4310 const char path_2[256];
4311 } chnotify_tests[] = {
4312 {"MKDIR", 1, 0, SHCNE_MKDIR, "C:\\shell32_cn_test\\test", ""},
4313 {"CREATE", 1, 0, SHCNE_CREATE, "C:\\shell32_cn_test\\test\\file.txt", ""},
4314 {"RMDIR", 1, 0, SHCNE_RMDIR, "C:\\shell32_cn_test\\test", ""},
4317 struct ChNotifyTest *exp_data;
4319 static LRESULT CALLBACK testwindow_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
4321 UINT signal = (UINT)lparam;
4324 case WM_USER_NOTIFY:
4325 if(exp_data->missing_events > 0){
4326 WCHAR *path1, *path2;
4327 LPCITEMIDLIST *pidls = (LPCITEMIDLIST*)wparam;
4329 ok(exp_data->signal == signal,
4330 "%s: expected notification type %x, got: %x\n",
4331 exp_data->id, exp_data->signal, signal);
4333 trace("verifying pidls for: %s\n", exp_data->id);
4334 path1 = make_wstr(exp_data->path_1);
4335 path2 = make_wstr(exp_data->path_2);
4336 verify_pidl(pidls[0], path1);
4337 verify_pidl(pidls[1], path2);
4338 HeapFree(GetProcessHeap(), 0, path1);
4339 HeapFree(GetProcessHeap(), 0, path2);
4341 exp_data->missing_events--;
4343 ok(0, "Didn't expect a WM_USER_NOTIFY message (event: %x)\n", signal);
4346 return DefWindowProc(hwnd, msg, wparam, lparam);
4349 static void register_testwindow_class(void)
4354 ZeroMemory(&cls, sizeof(cls));
4355 cls.cbSize = sizeof(cls);
4357 cls.lpfnWndProc = testwindow_wndproc;
4358 cls.hInstance = GetModuleHandleA(NULL);
4359 cls.lpszClassName = testwindow_class;
4362 ret = RegisterClassExA(&cls);
4363 ok(ret != 0, "RegisterClassExA failed: %d\n", GetLastError());
4366 /* SHCNF_FLUSH doesn't seem to work as advertised for SHCNF_PATHA, so we
4367 * have to poll repeatedly for the message to appear */
4368 static void do_events(void)
4371 while (exp_data->missing_events && (c++ < 10)){
4373 while(PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)){
4374 TranslateMessage(&msg);
4375 DispatchMessageA(&msg);
4377 if(exp_data->missing_events)
4380 trace("%s: took %d tries\n", exp_data->id, c);
4383 static void test_SHChangeNotify(void)
4388 BOOL br, has_unicode;
4389 SHChangeNotifyEntry entries[1];
4390 const CHAR root_dirA[] = "C:\\shell32_cn_test";
4391 const WCHAR root_dirW[] = {'C',':','\\','s','h','e','l','l','3','2','_','c','n','_','t','e','s','t',0};
4393 CreateDirectoryW(NULL, NULL);
4394 has_unicode = !(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED);
4396 register_testwindow_class();
4398 wnd = CreateWindowExA(0, testwindow_class, testwindow_class, 0,
4399 CW_USEDEFAULT, CW_USEDEFAULT, 130, 105,
4400 NULL, NULL, GetModuleHandleA(NULL), 0);
4401 ok(wnd != NULL, "Failed to make a window\n");
4403 br = CreateDirectoryA(root_dirA, NULL);
4404 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
4406 entries[0].pidl = NULL;
4408 hr = SHILCreateFromPath(root_dirW, (LPITEMIDLIST*)&entries[0].pidl, 0);
4410 hr = SHILCreateFromPath((LPCVOID)root_dirA, (LPITEMIDLIST*)&entries[0].pidl, 0);
4411 ok(hr == S_OK, "SHILCreateFromPath failed: 0x%08x\n", hr);
4412 entries[0].fRecursive = TRUE;
4414 notifyID = SHChangeNotifyRegister(wnd, SHCNRF_ShellLevel,
4415 SHCNE_ALLEVENTS, WM_USER_NOTIFY, 1, entries);
4416 ok(notifyID != 0, "Failed to register a window for change notifications\n");
4418 for(i = 0; i < sizeof(chnotify_tests) / sizeof(*chnotify_tests); ++i){
4419 exp_data = chnotify_tests + i;
4421 exp_data->missing_events = exp_data->notify_count;
4422 SHChangeNotify(exp_data->signal, SHCNF_PATHA | SHCNF_FLUSH,
4423 strlen(exp_data->path_1) > 0 ? exp_data->path_1 : NULL,
4424 strlen(exp_data->path_2) > 0 ? exp_data->path_2 : NULL);
4426 ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
4429 WCHAR *path1, *path2;
4431 path1 = make_wstr(exp_data->path_1);
4432 path2 = make_wstr(exp_data->path_2);
4434 exp_data->missing_events = exp_data->notify_count;
4435 SHChangeNotify(exp_data->signal, SHCNF_PATHW | SHCNF_FLUSH, path1, path2);
4437 ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
4439 HeapFree(GetProcessHeap(), 0, path1);
4440 HeapFree(GetProcessHeap(), 0, path2);
4444 SHChangeNotifyDeregister(notifyID);
4447 ILFree((LPITEMIDLIST)entries[0].pidl);
4448 br = RemoveDirectoryA(root_dirA);
4449 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4452 START_TEST(shlfolder)
4454 init_function_pointers();
4455 /* if OleInitialize doesn't get called, ParseDisplayName returns
4456 CO_E_NOTINITIALIZED for malformed directory names on win2k. */
4457 OleInitialize(NULL);
4459 test_ParseDisplayName();
4460 test_SHParseDisplayName();
4461 test_BindToObject();
4462 test_EnumObjects_and_CompareIDs();
4463 test_GetDisplayName();
4464 test_GetAttributesOf();
4465 test_SHGetPathFromIDList();
4466 test_CallForAttributes();
4467 test_FolderShortcut();
4468 test_ITEMIDLIST_format();
4469 test_SHGetFolderPathA();
4470 test_SHGetFolderPathAndSubDirA();
4471 test_LocalizedNames();
4472 test_SHCreateShellItem();
4473 test_SHCreateShellItemArray();
4474 test_desktop_IPersist();
4476 test_SHSimpleIDListFromPath();
4477 test_ParseDisplayNamePBC();
4478 test_SHGetNameFromIDList();
4479 test_SHGetItemFromDataObject();
4480 test_SHGetIDListFromObject();
4481 test_SHGetItemFromObject();
4482 test_ShellItemCompare();
4483 test_SHChangeNotify();
4484 test_ShellItemBindToHandler();
4485 test_ShellItemGetAttributes();