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];
2065 static const char desktopini_contents1[] =
2066 "[.ShellClassInfo]\r\n"
2067 "LocalizedResourceName=@";
2068 static const char desktopini_contents2[] =
2070 static WCHAR foldernameW[] = {'t','e','s','t','f','o','l','d','e','r',0};
2071 static const WCHAR folderdisplayW[] = {'F','o','l','d','e','r',' ','N','a','m','e',' ','R','e','s','o','u','r','c','e',0};
2073 /* create folder with desktop.ini and localized name in GetModuleFileNameA(NULL) */
2074 CreateDirectoryA(".\\testfolder", NULL);
2076 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")|FILE_ATTRIBUTE_SYSTEM);
2078 GetModuleFileNameA(NULL, resourcefile, MAX_PATH);
2080 file = CreateFileA(".\\testfolder\\desktop.ini", GENERIC_WRITE, 0, NULL,
2081 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2082 ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %i\n", GetLastError());
2083 ok(WriteFile(file, desktopini_contents1, strlen(desktopini_contents1), &res, NULL) &&
2084 WriteFile(file, resourcefile, strlen(resourcefile), &res, NULL) &&
2085 WriteFile(file, desktopini_contents2, strlen(desktopini_contents2), &res, NULL),
2086 "WriteFile failed %i\n", GetLastError());
2089 /* get IShellFolder for parent */
2090 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
2091 len = lstrlenA(cCurrDirA);
2094 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_LocalizedNames\n");
2097 if(cCurrDirA[len-1] == '\\')
2098 cCurrDirA[len-1] = 0;
2100 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
2102 hr = SHGetDesktopFolder(&IDesktopFolder);
2103 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
2105 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
2106 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
2108 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
2109 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
2111 IMalloc_Free(ppM, newPIDL);
2113 /* windows reads the display name from the resource */
2114 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, foldernameW, NULL, &newPIDL, 0);
2115 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
2117 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER, &strret);
2118 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2120 if (hr == S_OK && pStrRetToBufW)
2122 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2123 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2125 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
2126 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
2127 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2130 /* editing name is also read from the resource */
2131 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FOREDITING, &strret);
2132 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2134 if (hr == S_OK && pStrRetToBufW)
2136 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2137 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2139 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
2140 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
2141 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2144 /* parsing name is unchanged */
2145 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FORPARSING, &strret);
2146 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2148 if (hr == S_OK && pStrRetToBufW)
2150 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2151 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2152 ok (!lstrcmpiW(tempbufW, foldernameW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2155 IShellFolder_Release(IDesktopFolder);
2156 IShellFolder_Release(testIShellFolder);
2158 IMalloc_Free(ppM, newPIDL);
2161 DeleteFileA(".\\testfolder\\desktop.ini");
2162 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")&~FILE_ATTRIBUTE_SYSTEM);
2163 RemoveDirectoryA(".\\testfolder");
2166 static void test_SHCreateShellItem(void)
2168 IShellItem *shellitem, *shellitem2;
2169 IPersistIDList *persistidl;
2170 LPITEMIDLIST pidl_cwd=NULL, pidl_testfile, pidl_abstestfile, pidl_test, pidl_desktop;
2172 char curdirA[MAX_PATH];
2173 WCHAR curdirW[MAX_PATH];
2174 WCHAR fnbufW[MAX_PATH];
2175 IShellFolder *desktopfolder=NULL, *currentfolder=NULL;
2176 static WCHAR testfileW[] = {'t','e','s','t','f','i','l','e',0};
2178 GetCurrentDirectoryA(MAX_PATH, curdirA);
2180 if (!pSHCreateShellItem)
2182 win_skip("SHCreateShellItem isn't available\n");
2186 if (!lstrlenA(curdirA))
2188 win_skip("GetCurrentDirectoryA returned empty string, skipping test_SHCreateShellItem\n");
2192 if(pSHGetSpecialFolderLocation)
2194 ret = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
2195 ok(ret == S_OK, "Got 0x%08x\n", ret);
2199 win_skip("pSHGetSpecialFolderLocation missing.\n");
2200 pidl_desktop = NULL;
2203 MultiByteToWideChar(CP_ACP, 0, curdirA, -1, curdirW, MAX_PATH);
2205 ret = SHGetDesktopFolder(&desktopfolder);
2206 ok(SUCCEEDED(ret), "SHGetShellFolder returned %x\n", ret);
2208 ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2209 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2211 ret = IShellFolder_BindToObject(desktopfolder, pidl_cwd, NULL, &IID_IShellFolder, (void**)¤tfolder);
2212 ok(SUCCEEDED(ret), "BindToObject returned %x\n", ret);
2214 CreateTestFile(".\\testfile");
2216 ret = IShellFolder_ParseDisplayName(currentfolder, NULL, NULL, testfileW, NULL, &pidl_testfile, NULL);
2217 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2219 pidl_abstestfile = pILCombine(pidl_cwd, pidl_testfile);
2221 ret = pSHCreateShellItem(NULL, NULL, NULL, &shellitem);
2222 ok(ret == E_INVALIDARG, "SHCreateShellItem returned %x\n", ret);
2224 if (0) /* crashes on Windows XP */
2226 pSHCreateShellItem(NULL, NULL, pidl_cwd, NULL);
2227 pSHCreateShellItem(pidl_cwd, NULL, NULL, &shellitem);
2228 pSHCreateShellItem(NULL, currentfolder, NULL, &shellitem);
2229 pSHCreateShellItem(pidl_cwd, currentfolder, NULL, &shellitem);
2232 ret = pSHCreateShellItem(NULL, NULL, pidl_cwd, &shellitem);
2233 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2236 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2237 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2240 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2241 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2244 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2247 IPersistIDList_Release(persistidl);
2249 IShellItem_Release(shellitem);
2252 ret = pSHCreateShellItem(pidl_cwd, NULL, pidl_testfile, &shellitem);
2253 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2256 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2257 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2260 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2261 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2264 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2267 IPersistIDList_Release(persistidl);
2270 ret = IShellItem_GetParent(shellitem, &shellitem2);
2271 ok(SUCCEEDED(ret), "GetParent returned %x\n", ret);
2274 ret = IShellItem_QueryInterface(shellitem2, &IID_IPersistIDList, (void**)&persistidl);
2275 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2278 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2279 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2282 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2285 IPersistIDList_Release(persistidl);
2287 IShellItem_Release(shellitem2);
2290 IShellItem_Release(shellitem);
2293 ret = pSHCreateShellItem(NULL, currentfolder, pidl_testfile, &shellitem);
2294 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2297 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2298 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2301 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2302 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2305 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2308 IPersistIDList_Release(persistidl);
2310 IShellItem_Release(shellitem);
2313 /* if a parent pidl and shellfolder are specified, the shellfolder is ignored */
2314 ret = pSHCreateShellItem(pidl_cwd, desktopfolder, pidl_testfile, &shellitem);
2315 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2318 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2319 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2322 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2323 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2326 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2329 IPersistIDList_Release(persistidl);
2331 IShellItem_Release(shellitem);
2334 ret = pSHCreateShellItem(NULL, desktopfolder, pidl_testfile, &shellitem);
2335 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2338 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2339 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2342 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2343 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2346 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2349 IPersistIDList_Release(persistidl);
2352 IShellItem_Release(shellitem);
2355 ret = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
2356 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2359 ret = IShellItem_GetParent(shellitem, &shellitem2);
2360 ok(FAILED(ret), "Got 0x%08x\n", ret);
2361 if(SUCCEEDED(ret)) IShellItem_Release(shellitem2);
2362 IShellItem_Release(shellitem);
2365 /* SHCreateItemFromParsingName */
2366 if(pSHCreateItemFromParsingName)
2370 /* Crashes under windows 7 */
2371 ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, NULL);
2374 shellitem = (void*)0xdeadbeef;
2375 ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, (void**)&shellitem);
2376 ok(ret == E_INVALIDARG, "SHCreateItemFromParsingName returned %x\n", ret);
2377 ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2379 ret = pSHCreateItemFromParsingName(testfileW, NULL, &IID_IShellItem, (void**)&shellitem);
2380 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
2381 "SHCreateItemFromParsingName returned %x\n", ret);
2382 if(SUCCEEDED(ret)) IShellItem_Release(shellitem);
2384 lstrcpyW(fnbufW, curdirW);
2385 myPathAddBackslashW(fnbufW);
2386 lstrcatW(fnbufW, testfileW);
2388 ret = pSHCreateItemFromParsingName(fnbufW, NULL, &IID_IShellItem, (void**)&shellitem);
2389 ok(ret == S_OK, "SHCreateItemFromParsingName returned %x\n", ret);
2393 ret = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &tmp_fname);
2394 ok(ret == S_OK, "GetDisplayName returned %x\n", ret);
2397 ok(!lstrcmpW(fnbufW, tmp_fname), "strings not equal\n");
2398 CoTaskMemFree(tmp_fname);
2400 IShellItem_Release(shellitem);
2404 win_skip("No SHCreateItemFromParsingName\n");
2407 /* SHCreateItemFromIDList */
2408 if(pSHCreateItemFromIDList)
2412 /* Crashes under win7 */
2413 ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, NULL);
2416 ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, (void**)&shellitem);
2417 ok(ret == E_INVALIDARG, "SHCreateItemFromIDList returned %x\n", ret);
2419 ret = pSHCreateItemFromIDList(pidl_cwd, &IID_IShellItem, (void**)&shellitem);
2420 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2423 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2424 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2427 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2428 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2431 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2434 IPersistIDList_Release(persistidl);
2436 IShellItem_Release(shellitem);
2439 ret = pSHCreateItemFromIDList(pidl_testfile, &IID_IShellItem, (void**)&shellitem);
2440 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2443 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2444 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2447 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2448 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2451 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2454 IPersistIDList_Release(persistidl);
2456 IShellItem_Release(shellitem);
2460 win_skip("No SHCreateItemFromIDList\n");
2462 DeleteFileA(".\\testfile");
2463 pILFree(pidl_abstestfile);
2464 pILFree(pidl_testfile);
2465 pILFree(pidl_desktop);
2467 IShellFolder_Release(currentfolder);
2468 IShellFolder_Release(desktopfolder);
2471 static void test_SHGetNameFromIDList(void)
2473 IShellItem *shellitem;
2478 static const DWORD flags[] = {
2479 SIGDN_NORMALDISPLAY, SIGDN_PARENTRELATIVEPARSING,
2480 SIGDN_DESKTOPABSOLUTEPARSING,SIGDN_PARENTRELATIVEEDITING,
2481 SIGDN_DESKTOPABSOLUTEEDITING, /*SIGDN_FILESYSPATH, SIGDN_URL, */
2482 SIGDN_PARENTRELATIVEFORADDRESSBAR,SIGDN_PARENTRELATIVE, -1234};
2484 if(!pSHGetNameFromIDList)
2486 win_skip("SHGetNameFromIDList missing.\n");
2490 /* These should be available on any platform that passed the above test. */
2491 ok(pSHCreateShellItem != NULL, "SHCreateShellItem missing.\n");
2492 ok(pSHBindToParent != NULL, "SHBindToParent missing.\n");
2493 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
2494 ok(pStrRetToBufW != NULL, "StrRetToBufW missing.\n");
2498 /* Crashes under win7 */
2499 hres = pSHGetNameFromIDList(NULL, 0, NULL);
2502 hres = pSHGetNameFromIDList(NULL, 0, &name_string);
2503 ok(hres == E_INVALIDARG, "Got 0x%08x\n", hres);
2505 /* Test the desktop */
2506 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
2507 ok(hres == S_OK, "Got 0x%08x\n", hres);
2508 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2509 ok(hres == S_OK, "Got 0x%08x\n", hres);
2512 WCHAR *nameSI, *nameSH;
2513 WCHAR buf[MAX_PATH];
2514 HRESULT hrSI, hrSH, hrSF;
2519 SHGetDesktopFolder(&psf);
2520 for(i = 0; flags[i] != -1234; i++)
2522 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2523 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2524 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2525 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2526 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2527 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2529 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2530 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2534 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2536 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2538 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2540 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2541 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2543 IShellFolder_Release(psf);
2545 if(pSHGetPathFromIDListW){
2546 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2547 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2548 res = pSHGetPathFromIDListW(pidl, buf);
2549 ok(res == TRUE, "Got %d\n", res);
2550 if(SUCCEEDED(hrSI) && res)
2551 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2552 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2554 win_skip("pSHGetPathFromIDListW not available\n");
2556 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2557 todo_wine ok(hres == S_OK, "Got 0x%08x\n", hres);
2558 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2560 IShellItem_Release(shellitem);
2564 /* Test the control panel */
2565 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_CONTROLS, &pidl);
2566 ok(hres == S_OK, "Got 0x%08x\n", hres);
2567 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2568 ok(hres == S_OK, "Got 0x%08x\n", hres);
2571 WCHAR *nameSI, *nameSH;
2572 WCHAR buf[MAX_PATH];
2573 HRESULT hrSI, hrSH, hrSF;
2578 SHGetDesktopFolder(&psf);
2579 for(i = 0; flags[i] != -1234; i++)
2581 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2582 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2583 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2584 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2585 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2586 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2588 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2589 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2593 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2595 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2597 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2599 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2600 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2602 IShellFolder_Release(psf);
2604 if(pSHGetPathFromIDListW){
2605 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2606 ok(hrSI == E_INVALIDARG, "Got 0x%08x\n", hrSI);
2607 res = pSHGetPathFromIDListW(pidl, buf);
2608 ok(res == FALSE, "Got %d\n", res);
2609 if(SUCCEEDED(hrSI) && res)
2610 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2611 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2613 win_skip("pSHGetPathFromIDListW not available\n");
2615 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2616 todo_wine ok(hres == E_NOTIMPL /* Win7 */ || hres == S_OK /* Vista */,
2617 "Got 0x%08x\n", hres);
2618 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2620 IShellItem_Release(shellitem);
2625 static void test_SHGetItemFromDataObject(void)
2627 IShellFolder *psfdesktop;
2632 if(!pSHGetItemFromDataObject)
2634 win_skip("No SHGetItemFromDataObject.\n");
2640 /* Crashes under win7 */
2641 hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, NULL);
2644 hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, (void**)&psv);
2645 ok(hres == E_INVALIDARG, "got 0x%08x\n", hres);
2647 SHGetDesktopFolder(&psfdesktop);
2649 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
2650 ok(hres == S_OK, "got 0x%08x\n", hres);
2657 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
2658 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
2659 ok(hres == S_OK, "got 0x%08x\n", hres);
2662 LPITEMIDLIST apidl[5];
2665 for(count = 0; count < 5; count++)
2666 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
2671 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
2672 &IID_IDataObject, NULL, (void**)&pdo);
2673 ok(hres == S_OK, "got 0x%08x\n", hres);
2676 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2677 ok(hres == S_OK, "got 0x%08x\n", hres);
2678 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2679 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2680 ok(hres == S_OK, "got 0x%08x\n", hres);
2681 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2682 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2683 ok(hres == S_OK, "got 0x%08x\n", hres);
2684 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2685 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2686 ok(hres == S_OK, "got 0x%08x\n", hres);
2687 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2688 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2689 ok(hres == S_OK, "got 0x%08x\n", hres);
2690 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2692 IDataObject_Release(pdo);
2696 skip("No file(s) found - skipping single-file test.\n");
2700 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
2701 &IID_IDataObject, NULL, (void**)&pdo);
2702 ok(hres == S_OK, "got 0x%08x\n", hres);
2705 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2706 ok(hres == S_OK, "got 0x%08x\n", hres);
2707 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2708 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2709 ok(hres == S_OK, "got 0x%08x\n", hres);
2710 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2711 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2712 ok(hres == S_OK, "got 0x%08x\n", hres);
2713 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2714 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2715 ok(hres == S_OK, "got 0x%08x\n", hres);
2716 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2717 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2718 ok(hres == E_FAIL, "got 0x%08x\n", hres);
2719 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2720 IDataObject_Release(pdo);
2724 skip("zero or one file found - skipping multi-file test.\n");
2726 for(i = 0; i < count; i++)
2729 IEnumIDList_Release(peidl);
2732 IShellView_Release(psv);
2735 IShellFolder_Release(psfdesktop);
2738 static void test_ShellItemCompare(void)
2740 IShellItem *psi[9]; /* a\a, a\b, a\c, b\a, .. */
2741 IShellItem *psi_a = NULL, *psi_b = NULL, *psi_c = NULL;
2742 IShellFolder *psf_desktop, *psf_current;
2743 LPITEMIDLIST pidl_cwd;
2744 WCHAR curdirW[MAX_PATH];
2747 static const WCHAR filesW[][9] = {
2748 {'a','\\','a',0}, {'a','\\','b',0}, {'a','\\','c',0},
2749 {'b','\\','a',0}, {'b','\\','b',0}, {'b','\\','c',0},
2750 {'c','\\','a',0}, {'c','\\','b',0}, {'c','\\','c',0} };
2754 if(!pSHCreateShellItem)
2756 win_skip("SHCreateShellItem missing.\n");
2760 GetCurrentDirectoryW(MAX_PATH, curdirW);
2761 if(!lstrlenW(curdirW))
2763 skip("Failed to get current directory, skipping.\n");
2767 CreateDirectoryA(".\\a", NULL);
2768 CreateDirectoryA(".\\b", NULL);
2769 CreateDirectoryA(".\\c", NULL);
2770 CreateTestFile(".\\a\\a");
2771 CreateTestFile(".\\a\\b");
2772 CreateTestFile(".\\a\\c");
2773 CreateTestFile(".\\b\\a");
2774 CreateTestFile(".\\b\\b");
2775 CreateTestFile(".\\b\\c");
2776 CreateTestFile(".\\c\\a");
2777 CreateTestFile(".\\c\\b");
2778 CreateTestFile(".\\c\\c");
2780 SHGetDesktopFolder(&psf_desktop);
2781 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2782 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2783 hr = IShellFolder_BindToObject(psf_desktop, pidl_cwd, NULL, &IID_IShellFolder, (void**)&psf_current);
2784 ok(SUCCEEDED(hr), "BindToObject returned %x\n", hr);
2785 IShellFolder_Release(psf_desktop);
2787 /* Generate ShellItems for the files */
2788 ZeroMemory(&psi, sizeof(IShellItem*)*9);
2790 for(i = 0; i < 9; i++)
2792 LPITEMIDLIST pidl_testfile = NULL;
2794 hr = IShellFolder_ParseDisplayName(psf_current, NULL, NULL, (LPWSTR)filesW[i],
2795 NULL, &pidl_testfile, NULL);
2796 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2799 hr = pSHCreateShellItem(NULL, NULL, pidl_testfile, &psi[i]);
2800 ok(hr == S_OK, "Got 0x%08x\n", hr);
2801 pILFree(pidl_testfile);
2803 if(FAILED(hr)) failed = TRUE;
2807 skip("Failed to create all shellitems.\n");
2811 /* Generate ShellItems for the folders */
2812 hr = IShellItem_GetParent(psi[0], &psi_a);
2813 ok(hr == S_OK, "Got 0x%08x\n", hr);
2814 if(FAILED(hr)) failed = TRUE;
2815 hr = IShellItem_GetParent(psi[3], &psi_b);
2816 ok(hr == S_OK, "Got 0x%08x\n", hr);
2817 if(FAILED(hr)) failed = TRUE;
2818 hr = IShellItem_GetParent(psi[6], &psi_c);
2819 ok(hr == S_OK, "Got 0x%08x\n", hr);
2820 if(FAILED(hr)) failed = TRUE;
2824 skip("Failed to create shellitems.\n");
2830 /* Crashes on native (win7, winxp) */
2831 hr = IShellItem_Compare(psi_a, NULL, 0, NULL);
2832 hr = IShellItem_Compare(psi_a, psi_b, 0, NULL);
2833 hr = IShellItem_Compare(psi_a, NULL, 0, &order);
2837 for(i = 0; i < 9; i++)
2839 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_DISPLAY, &order);
2840 ok(hr == S_OK, "Got 0x%08x\n", hr);
2841 ok(order == 0, "Got order %d\n", order);
2842 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_CANONICAL, &order);
2843 ok(hr == S_OK, "Got 0x%08x\n", hr);
2844 ok(order == 0, "Got order %d\n", order);
2845 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_ALLFIELDS, &order);
2846 ok(hr == S_OK, "Got 0x%08x\n", hr);
2847 ok(order == 0, "Got order %d\n", order);
2851 /* a\b:a\a , a\b:a\c, a\b:a\b */
2852 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_DISPLAY, &order);
2853 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2854 ok(order == 1, "Got order %d\n", order);
2855 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_DISPLAY, &order);
2856 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2857 ok(order == -1, "Got order %d\n", order);
2858 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_DISPLAY, &order);
2859 ok(hr == S_OK, "Got 0x%08x\n", hr);
2860 ok(order == 0, "Got order %d\n", order);
2862 /* b\b:a\b, b\b:c\b, b\b:c\b */
2863 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_DISPLAY, &order);
2864 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2865 ok(order == 1, "Got order %d\n", order);
2866 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_DISPLAY, &order);
2867 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2868 ok(order == -1, "Got order %d\n", order);
2869 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_DISPLAY, &order);
2870 ok(hr == S_OK, "Got 0x%08x\n", hr);
2871 ok(order == 0, "Got order %d\n", order);
2873 /* b:a\a, b:a\c, b:a\b */
2874 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_DISPLAY, &order);
2875 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2876 todo_wine ok(order == 1, "Got order %d\n", order);
2877 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_DISPLAY, &order);
2878 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2879 todo_wine ok(order == 1, "Got order %d\n", order);
2880 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_DISPLAY, &order);
2881 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2882 todo_wine ok(order == 1, "Got order %d\n", order);
2884 /* b:c\a, b:c\c, b:c\b */
2885 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_DISPLAY, &order);
2886 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2887 ok(order == -1, "Got order %d\n", order);
2888 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_DISPLAY, &order);
2889 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2890 ok(order == -1, "Got order %d\n", order);
2891 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_DISPLAY, &order);
2892 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2893 ok(order == -1, "Got order %d\n", order);
2895 /* a\b:a\a , a\b:a\c, a\b:a\b */
2896 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_CANONICAL, &order);
2897 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2898 ok(order == 1, "Got order %d\n", order);
2899 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_CANONICAL, &order);
2900 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2901 ok(order == -1, "Got order %d\n", order);
2902 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_CANONICAL, &order);
2903 ok(hr == S_OK, "Got 0x%08x\n", hr);
2904 ok(order == 0, "Got order %d\n", order);
2906 /* b\b:a\b, b\b:c\b, b\b:c\b */
2907 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_CANONICAL, &order);
2908 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2909 ok(order == 1, "Got order %d\n", order);
2910 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_CANONICAL, &order);
2911 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2912 ok(order == -1, "Got order %d\n", order);
2913 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_CANONICAL, &order);
2914 ok(hr == S_OK, "Got 0x%08x\n", hr);
2915 ok(order == 0, "Got order %d\n", order);
2917 /* b:a\a, b:a\c, b:a\b */
2918 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_CANONICAL, &order);
2919 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2920 todo_wine ok(order == 1, "Got order %d\n", order);
2921 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_CANONICAL, &order);
2922 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2923 todo_wine ok(order == 1, "Got order %d\n", order);
2924 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_CANONICAL, &order);
2925 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2926 todo_wine ok(order == 1, "Got order %d\n", order);
2928 /* b:c\a, b:c\c, b:c\b */
2929 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_CANONICAL, &order);
2930 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2931 ok(order == -1, "Got order %d\n", order);
2932 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_CANONICAL, &order);
2933 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2934 ok(order == -1, "Got order %d\n", order);
2935 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_CANONICAL, &order);
2936 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2937 ok(order == -1, "Got order %d\n", order);
2940 IShellFolder_Release(psf_current);
2942 DeleteFileA(".\\a\\a");
2943 DeleteFileA(".\\a\\b");
2944 DeleteFileA(".\\a\\c");
2945 DeleteFileA(".\\b\\a");
2946 DeleteFileA(".\\b\\b");
2947 DeleteFileA(".\\b\\c");
2948 DeleteFileA(".\\c\\a");
2949 DeleteFileA(".\\c\\b");
2950 DeleteFileA(".\\c\\c");
2951 RemoveDirectoryA(".\\a");
2952 RemoveDirectoryA(".\\b");
2953 RemoveDirectoryA(".\\c");
2955 if(psi_a) IShellItem_Release(psi_a);
2956 if(psi_b) IShellItem_Release(psi_b);
2957 if(psi_c) IShellItem_Release(psi_c);
2959 for(i = 0; i < 9; i++)
2960 if(psi[i]) IShellItem_Release(psi[i]);
2963 /**************************************************************/
2964 /* IUnknown implementation for counting QueryInterface calls. */
2966 const IUnknownVtbl *lpVtbl;
2974 static HRESULT WINAPI unk_fnQueryInterface(IUnknown *iunk, REFIID riid, void** punk)
2976 IUnknownImpl *This = (IUnknownImpl*)iunk;
2978 for(i = found = 0; This->ifaces[i].id != NULL; i++)
2980 if(IsEqualIID(This->ifaces[i].id, riid))
2982 This->ifaces[i].count++;
2989 return E_NOINTERFACE;
2992 static ULONG WINAPI unk_fnAddRef(IUnknown *iunk)
2997 static ULONG WINAPI unk_fnRelease(IUnknown *iunk)
3002 static const IUnknownVtbl vt_IUnknown = {
3003 unk_fnQueryInterface,
3008 static void test_SHGetIDListFromObject(void)
3010 IUnknownImpl *punkimpl;
3011 IShellFolder *psfdesktop;
3013 LPITEMIDLIST pidl, pidl_desktop;
3016 struct if_count ifaces[] =
3017 { {&IID_IPersistIDList, 0},
3018 {&IID_IPersistFolder2, 0},
3019 {&IID_IDataObject, 0},
3020 {&IID_IParentAndItem, 0},
3021 {&IID_IFolderView, 0},
3024 if(!pSHGetIDListFromObject)
3026 win_skip("SHGetIDListFromObject missing.\n");
3030 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
3034 /* Crashes native */
3035 pSHGetIDListFromObject(NULL, NULL);
3036 pSHGetIDListFromObject((void*)0xDEADBEEF, NULL);
3039 hres = pSHGetIDListFromObject(NULL, &pidl);
3040 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3042 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
3043 punkimpl->lpVtbl = &vt_IUnknown;
3044 punkimpl->ifaces = ifaces;
3045 punkimpl->unknown = 0;
3047 hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
3048 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3049 ok(ifaces[0].count, "interface not requested.\n");
3050 ok(ifaces[1].count, "interface not requested.\n");
3051 ok(ifaces[2].count, "interface not requested.\n");
3053 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3054 "interface not requested.\n");
3055 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3056 "interface not requested.\n");
3058 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3059 HeapFree(GetProcessHeap(), 0, punkimpl);
3061 pidl_desktop = NULL;
3062 pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3063 ok(pidl_desktop != NULL, "Failed to get desktop pidl.\n");
3065 SHGetDesktopFolder(&psfdesktop);
3067 /* Test IShellItem */
3068 if(pSHCreateShellItem)
3070 IShellItem *shellitem;
3071 hres = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
3072 ok(hres == S_OK, "got 0x%08x\n", hres);
3075 hres = pSHGetIDListFromObject((IUnknown*)shellitem, &pidl);
3076 ok(hres == S_OK, "got 0x%08x\n", hres);
3079 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3082 IShellItem_Release(shellitem);
3086 skip("no SHCreateShellItem.\n");
3088 /* Test IShellFolder */
3089 hres = pSHGetIDListFromObject((IUnknown*)psfdesktop, &pidl);
3090 ok(hres == S_OK, "got 0x%08x\n", hres);
3093 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3097 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
3098 ok(hres == S_OK, "got 0x%08x\n", hres);
3105 /* Test IFolderView */
3106 hres = pSHGetIDListFromObject((IUnknown*)psv, &pidl);
3107 ok(hres == S_OK, "got 0x%08x\n", hres);
3110 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3114 /* Test IDataObject */
3115 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3116 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
3117 ok(hres == S_OK, "got 0x%08x\n", hres);
3120 LPITEMIDLIST apidl[5];
3122 for(count = 0; count < 5; count++)
3123 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3128 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
3129 &IID_IDataObject, NULL, (void**)&pdo);
3130 ok(hres == S_OK, "got 0x%08x\n", hres);
3133 pidl = (void*)0xDEADBEEF;
3134 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3135 ok(hres == S_OK, "got 0x%08x\n", hres);
3136 ok(pidl != NULL, "pidl is NULL.\n");
3137 ok(ILIsEqual(pidl, apidl[0]), "pidl not equal.\n");
3140 IDataObject_Release(pdo);
3144 skip("No files found - skipping single-file test.\n");
3148 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
3149 &IID_IDataObject, NULL, (void**)&pdo);
3150 ok(hres == S_OK, "got 0x%08x\n", hres);
3153 pidl = (void*)0xDEADBEEF;
3154 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3155 ok(hres == E_NOINTERFACE || hres == E_FAIL /*Vista*/,
3156 "got 0x%08x\n", hres);
3157 ok(pidl == NULL, "pidl is not NULL.\n");
3159 IDataObject_Release(pdo);
3163 skip("zero or one file found - skipping multi-file test.\n");
3165 for(i = 0; i < count; i++)
3168 IEnumIDList_Release(peidl);
3171 IShellView_Release(psv);
3174 IShellFolder_Release(psfdesktop);
3175 pILFree(pidl_desktop);
3178 static void test_SHGetItemFromObject(void)
3180 IUnknownImpl *punkimpl;
3181 IShellFolder *psfdesktop;
3186 struct if_count ifaces[] =
3187 { {&IID_IPersistIDList, 0},
3188 {&IID_IPersistFolder2, 0},
3189 {&IID_IDataObject, 0},
3190 {&IID_IParentAndItem, 0},
3191 {&IID_IFolderView, 0},
3194 if(!pSHGetItemFromObject)
3196 skip("No SHGetItemFromObject.\n");
3200 SHGetDesktopFolder(&psfdesktop);
3204 /* Crashes with Windows 7 */
3205 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IUnknown, NULL);
3206 hres = pSHGetItemFromObject(NULL, &IID_IUnknown, NULL);
3207 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, NULL, (void**)&punk);
3210 hres = pSHGetItemFromObject(NULL, &IID_IUnknown, (void**)&punk);
3211 ok(hres == E_NOINTERFACE, "Got 0x%08x\n", hres);
3213 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
3214 punkimpl->lpVtbl = &vt_IUnknown;
3215 punkimpl->ifaces = ifaces;
3216 punkimpl->unknown = 0;
3218 /* The same as SHGetIDListFromObject */
3219 hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
3220 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3221 ok(ifaces[0].count, "interface not requested.\n");
3222 ok(ifaces[1].count, "interface not requested.\n");
3223 ok(ifaces[2].count, "interface not requested.\n");
3225 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3226 "interface not requested.\n");
3227 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3228 "interface not requested.\n");
3230 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3231 HeapFree(GetProcessHeap(), 0, punkimpl);
3233 /* Test IShellItem */
3234 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IShellItem, (void**)&psi);
3235 ok(hres == S_OK, "Got 0x%08x\n", hres);
3239 hres = pSHGetItemFromObject((IUnknown*)psi, &IID_IShellItem, (void**)&psi2);
3240 ok(hres == S_OK, "Got 0x%08x\n", hres);
3244 ok(psi == psi2, "Different instances (%p != %p).\n", psi, psi2);
3245 IShellItem_Release(psi2);
3247 IShellItem_Release(psi);
3250 IShellFolder_Release(psfdesktop);
3253 static void test_SHCreateShellItemArray(void)
3255 IShellFolder *pdesktopsf, *psf;
3256 IShellItemArray *psia;
3259 WCHAR cTestDirW[MAX_PATH];
3260 LPITEMIDLIST pidl_testdir, pidl;
3261 static const WCHAR testdirW[] = {'t','e','s','t','d','i','r',0};
3263 if(!pSHCreateShellItemArray) {
3264 skip("No pSHCreateShellItemArray!\n");
3268 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
3272 /* Crashes under native */
3273 pSHCreateShellItemArray(NULL, NULL, 0, NULL, NULL);
3274 pSHCreateShellItemArray(NULL, NULL, 1, NULL, NULL);
3275 pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, NULL);
3276 pSHCreateShellItemArray(pidl, NULL, 0, NULL, NULL);
3279 hr = pSHCreateShellItemArray(NULL, NULL, 0, NULL, &psia);
3280 ok(hr == E_POINTER, "got 0x%08x\n", hr);
3282 SHGetDesktopFolder(&pdesktopsf);
3283 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, &psia);
3284 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3286 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 1, NULL, &psia);
3287 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3289 pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
3290 hr = pSHCreateShellItemArray(pidl, NULL, 0, NULL, &psia);
3291 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3294 GetCurrentDirectoryW(MAX_PATH, cTestDirW);
3295 myPathAddBackslashW(cTestDirW);
3296 lstrcatW(cTestDirW, testdirW);
3298 CreateFilesFolders();
3300 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, cTestDirW, NULL, &pidl_testdir, 0);
3301 ok(hr == S_OK, "got 0x%08x\n", hr);
3304 hr = IShellFolder_BindToObject(pdesktopsf, pidl_testdir, NULL, (REFIID)&IID_IShellFolder,
3306 ok(hr == S_OK, "Got 0x%08x\n", hr);
3308 IShellFolder_Release(pdesktopsf);
3312 skip("Failed to set up environment for SHCreateShellItemArray tests.\n");
3313 pILFree(pidl_testdir);
3318 hr = IShellFolder_EnumObjects(psf, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &peidl);
3319 ok(hr == S_OK, "Got %08x\n", hr);
3322 LPITEMIDLIST apidl[5];
3323 UINT done, numitems, i;
3325 for(done = 0; done < 5; done++)
3326 if(IEnumIDList_Next(peidl, 1, &apidl[done], NULL) != S_OK)
3328 ok(done == 5, "Got %d pidls\n", done);
3329 IEnumIDList_Release(peidl);
3331 /* Create a ShellItemArray */
3332 hr = pSHCreateShellItemArray(NULL, psf, done, (LPCITEMIDLIST*)apidl, &psia);
3333 ok(hr == S_OK, "Got 0x%08x\n", hr);
3340 /* Crashes in Windows 7 */
3341 hr = IShellItemArray_GetCount(psia, NULL);
3344 IShellItemArray_GetCount(psia, &numitems);
3345 ok(numitems == done, "Got %d, expected %d\n", numitems, done);
3347 hr = IShellItemArray_GetItemAt(psia, numitems, &psi);
3348 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3350 /* Compare all the items */
3351 for(i = 0; i < numitems; i++)
3353 LPITEMIDLIST pidl_abs;
3354 pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3356 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3357 ok(hr == S_OK, "(%d) Failed with 0x%08x\n", i, hr);
3360 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3361 ok(hr == S_OK, "Got 0x%08x\n", hr);
3364 ok(ILIsEqual(pidl_abs, pidl), "Pidl not equal.\n");
3367 IShellItem_Release(psi);
3371 for(i = 0; i < done; i++)
3373 IShellItemArray_Release(psia);
3377 /* SHCreateShellItemArrayFromShellItem */
3378 if(pSHCreateShellItemArrayFromShellItem)
3384 /* Crashes under Windows 7 */
3385 hr = pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, NULL);
3386 hr = pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, (void**)&psia);
3387 hr = pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, NULL);
3390 hr = pSHCreateItemFromIDList(pidl_testdir, &IID_IShellItem, (void**)&psi);
3391 ok(hr == S_OK, "Got 0x%08x\n", hr);
3394 hr = pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, (void**)&psia);
3395 ok(hr == S_OK, "Got 0x%08x\n", hr);
3400 hr = IShellItemArray_GetCount(psia, &count);
3401 ok(hr == S_OK, "Got 0x%08x\n", hr);
3402 ok(count == 1, "Got count %d\n", count);
3403 hr = IShellItemArray_GetItemAt(psia, 0, &psi2);
3404 ok(hr == S_OK, "Got 0x%08x\n", hr);
3406 ok(psi != psi2, "ShellItems are of the same instance.\n");
3409 LPITEMIDLIST pidl1, pidl2;
3410 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl1);
3411 ok(hr == S_OK, "Got 0x%08x\n", hr);
3412 ok(pidl1 != NULL, "pidl1 was null.\n");
3413 hr = pSHGetIDListFromObject((IUnknown*)psi2, &pidl2);
3414 ok(hr == S_OK, "Got 0x%08x\n", hr);
3415 ok(pidl2 != NULL, "pidl2 was null.\n");
3416 ok(ILIsEqual(pidl1, pidl2), "pidls not equal.\n");
3419 IShellItem_Release(psi2);
3421 hr = IShellItemArray_GetItemAt(psia, 1, &psi2);
3422 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3423 IShellItemArray_Release(psia);
3425 IShellItem_Release(psi);
3429 skip("No SHCreateShellItemArrayFromShellItem.\n");
3431 if(pSHCreateShellItemArrayFromDataObject)
3437 /* Crashes under Windows 7 */
3438 hr = pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, NULL);
3440 hr = pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, (void**)&psia);
3441 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3443 hr = IShellFolder_CreateViewObject(psf, NULL, &IID_IShellView, (void**)&psv);
3444 ok(hr == S_OK, "got 0x%08x\n", hr);
3451 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3452 hr = IShellFolder_EnumObjects(psf, NULL, enum_flags, &peidl);
3453 ok(hr == S_OK, "got 0x%08x\n", hr);
3456 LPITEMIDLIST apidl[5];
3459 for(count = 0; count < 5; count++)
3460 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3462 ok(count == 5, "Got %d\n", count);
3466 hr = IShellFolder_GetUIObjectOf(psf, NULL, count, (LPCITEMIDLIST*)apidl,
3467 &IID_IDataObject, NULL, (void**)&pdo);
3468 ok(hr == S_OK, "Got 0x%08x\n", hr);
3471 hr = pSHCreateShellItemArrayFromDataObject(pdo, &IID_IShellItemArray,
3473 ok(hr == S_OK, "Got 0x%08x\n", hr);
3477 hr = IShellItemArray_GetCount(psia, &count_sia);
3478 ok(count_sia == count, "Counts differ (%d, %d)\n", count, count_sia);
3479 for(i = 0; i < count_sia; i++)
3481 LPITEMIDLIST pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3483 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3484 ok(hr == S_OK, "Got 0x%08x\n", hr);
3488 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3489 ok(hr == S_OK, "Got 0x%08x\n", hr);
3490 ok(pidl != NULL, "pidl as NULL.\n");
3491 ok(ILIsEqual(pidl, pidl_abs), "pidls differ.\n");
3493 IShellItem_Release(psi);
3498 IShellItemArray_Release(psia);
3501 IDataObject_Release(pdo);
3503 for(i = 0; i < count; i++)
3507 skip("No files found - skipping test.\n");
3509 IEnumIDList_Release(peidl);
3511 IShellView_Release(psv);
3515 skip("No SHCreateShellItemArrayFromDataObject.\n");
3517 IShellFolder_Release(psf);
3518 pILFree(pidl_testdir);
3522 static void test_ShellItemBindToHandler(void)
3525 LPITEMIDLIST pidl_desktop;
3528 if(!pSHCreateShellItem)
3530 skip("SHCreateShellItem missing.\n");
3534 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3535 ok(hr == S_OK, "Got 0x%08x\n", hr);
3538 hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
3539 ok(hr == S_OK, "Got 0x%08x\n", hr);
3543 IPersistFolder2 *ppf2;
3548 /* Crashes under Windows 7 */
3549 hr = IShellItem_BindToHandler(psi, NULL, NULL, NULL, NULL);
3550 hr = IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, NULL);
3552 hr = IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, (void**)&punk);
3553 ok(hr == MK_E_NOOBJECT, "Got 0x%08x\n", hr);
3556 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IShellFolder, (void**)&punk);
3557 ok(hr == S_OK, "Got 0x%08x\n", hr);
3558 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3559 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IPersistFolder2, (void**)&ppf2);
3560 ok(hr == S_OK, "Got 0x%08x\n", hr);
3563 LPITEMIDLIST pidl_tmp;
3564 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl_tmp);
3565 ok(hr == S_OK, "Got 0x%08x\n", hr);
3568 ok(ILIsEqual(pidl_desktop, pidl_tmp), "Pidl not equal (%p, %p)\n", pidl_desktop, pidl_tmp);
3571 IPersistFolder2_Release(ppf2);
3574 /* BHID_SFUIObject */
3575 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IDataObject, (void**)&punk);
3576 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3577 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3578 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IContextMenu, (void**)&punk);
3579 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3580 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3582 /* BHID_DataObject */
3583 hr = IShellItem_BindToHandler(psi, NULL, &BHID_DataObject, &IID_IDataObject, (void**)&punk);
3584 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3585 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3589 /* BHID_SFViewObject */
3590 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellView, (void**)&punk);
3591 ok(hr == S_OK, "Got 0x%08x\n", hr);
3592 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3593 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellFolderView, (void**)&punk);
3594 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3595 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3598 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IStream, (void**)&punk);
3599 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3600 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3601 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IUnknown, (void**)&punk);
3602 ok(hr == S_OK, "Got 0x%08x\n", hr);
3603 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3606 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IStream, (void**)&punk);
3607 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3608 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3609 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IUnknown, (void**)&punk);
3610 ok(hr == S_OK, "Got 0x%08x\n", hr);
3611 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3613 /* BHID_StorageEnum */
3614 hr = IShellItem_BindToHandler(psi, NULL, &BHID_StorageEnum, &IID_IEnumShellItems, (void**)&punk);
3615 ok(hr == S_OK, "Got 0x%08x\n", hr);
3616 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3619 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_IUnknown, (void**)&punk);
3620 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3621 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3623 /* BHID_EnumItems */
3624 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumItems, &IID_IEnumShellItems, (void**)&punk);
3625 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3626 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3629 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Filter, &IID_IUnknown, (void**)&punk);
3630 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3631 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3633 /* BHID_LinkTargetItem */
3634 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IShellItem, (void**)&punk);
3635 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3636 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3637 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IUnknown, (void**)&punk);
3638 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3639 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3641 /* BHID_PropertyStore */
3642 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStore, (void**)&punk);
3643 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3644 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3645 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStoreFactory, (void**)&punk);
3646 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3647 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3649 /* BHID_ThumbnailHandler */
3650 hr = IShellItem_BindToHandler(psi, NULL, &BHID_ThumbnailHandler, &IID_IUnknown, (void**)&punk);
3651 ok(hr == E_INVALIDARG || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3652 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3654 /* BHID_AssociationArray */
3655 hr = IShellItem_BindToHandler(psi, NULL, &BHID_AssociationArray, &IID_IQueryAssociations, (void**)&punk);
3656 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3657 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3659 /* BHID_EnumAssocHandlers */
3660 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumAssocHandlers, &IID_IUnknown, (void**)&punk);
3661 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3662 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3665 IShellItem_Release(psi);
3668 skip("Failed to create ShellItem.\n");
3670 pILFree(pidl_desktop);
3673 void test_ShellItemGetAttributes(void)
3676 LPITEMIDLIST pidl_desktop;
3680 if(!pSHCreateShellItem)
3682 skip("SHCreateShellItem missing.\n");
3686 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3687 ok(hr == S_OK, "Got 0x%08x\n", hr);
3690 hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
3691 ok(hr == S_OK, "Got 0x%08x\n", hr);
3692 pILFree(pidl_desktop);
3696 skip("Skipping tests.");
3702 /* Crashes on native (Win 7) */
3703 hr = IShellItem_GetAttributes(psi, 0, NULL);
3704 ok(hr == S_OK, "Got 0x%08x\n", hr);
3707 /* Test GetAttributes on the desktop folder. */
3709 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER, &sfgao);
3710 ok(hr == S_OK || broken(hr == E_FAIL) /* <Vista */, "Got 0x%08x\n", hr);
3711 ok(sfgao == SFGAO_FOLDER || broken(sfgao == 0) /* <Vista */, "Got 0x%08x\n", sfgao);
3713 IShellItem_Release(psi);
3716 static void test_SHParseDisplayName(void)
3718 LPITEMIDLIST pidl1, pidl2;
3719 IShellFolder *desktop;
3720 WCHAR dirW[MAX_PATH];
3725 if (!pSHParseDisplayName)
3727 win_skip("SHParseDisplayName isn't available\n");
3733 /* crashes on native */
3734 hr = pSHParseDisplayName(NULL, NULL, NULL, 0, NULL);
3736 hr = pSHParseDisplayName(nameW, NULL, NULL, 0, NULL);
3739 pidl1 = (LPITEMIDLIST)0xdeadbeef;
3740 hr = pSHParseDisplayName(NULL, NULL, &pidl1, 0, NULL);
3741 ok(broken(hr == E_OUTOFMEMORY) /* < Vista */ ||
3742 hr == E_INVALIDARG, "failed %08x\n", hr);
3743 ok(pidl1 == 0, "expected null ptr, got %p\n", pidl1);
3747 hr = pSHParseDisplayName(nameW, NULL, &pidl1, 0, NULL);
3748 ok(hr == S_OK, "failed %08x\n", hr);
3749 hr = SHGetDesktopFolder(&desktop);
3750 ok(hr == S_OK, "failed %08x\n", hr);
3751 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, nameW, NULL, &pidl2, NULL);
3752 ok(hr == S_OK, "failed %08x\n", hr);
3753 ret = pILIsEqual(pidl1, pidl2);
3754 ok(ret == TRUE, "expected equal idls\n");
3759 GetWindowsDirectoryW( dirW, MAX_PATH );
3761 hr = pSHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
3762 ok(hr == S_OK, "failed %08x\n", hr);
3763 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, dirW, NULL, &pidl2, NULL);
3764 ok(hr == S_OK, "failed %08x\n", hr);
3766 ret = pILIsEqual(pidl1, pidl2);
3767 ok(ret == TRUE, "expected equal idls\n");
3771 IShellFolder_Release(desktop);
3774 static void test_desktop_IPersist(void)
3776 IShellFolder *desktop;
3778 IPersistFolder2 *ppf2;
3782 hr = SHGetDesktopFolder(&desktop);
3783 ok(hr == S_OK, "failed %08x\n", hr);
3785 hr = IShellFolder_QueryInterface(desktop, &IID_IPersist, (void**)&persist);
3786 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* NT4, W9X */, "failed %08x\n", hr);
3792 /* crashes on native */
3793 hr = IPersist_GetClassID(persist, NULL);
3795 memset(&clsid, 0, sizeof(clsid));
3796 hr = IPersist_GetClassID(persist, &clsid);
3797 ok(hr == S_OK, "failed %08x\n", hr);
3798 ok(IsEqualIID(&CLSID_ShellDesktop, &clsid), "Expected CLSID_ShellDesktop\n");
3799 IPersist_Release(persist);
3802 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder2, (void**)&ppf2);
3803 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* pre-Vista */, "failed %08x\n", hr);
3806 IPersistFolder *ppf;
3808 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder, (void**)&ppf);
3809 ok(hr == S_OK, "IID_IPersistFolder2 without IID_IPersistFolder.\n");
3811 IPersistFolder_Release(ppf);
3814 hr = IPersistFolder2_Initialize(ppf2, NULL);
3815 ok(hr == S_OK, "got %08x\n", hr);
3819 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl);
3820 ok(hr == S_OK, "got %08x\n", hr);
3821 ok(pidl != NULL, "pidl was NULL.\n");
3822 if(SUCCEEDED(hr)) pILFree(pidl);
3824 IPersistFolder2_Release(ppf2);
3827 IShellFolder_Release(desktop);
3830 static void test_GetUIObject(void)
3832 IShellFolder *psf_desktop;
3836 WCHAR path[MAX_PATH];
3837 const WCHAR filename[] =
3838 {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
3840 if(!pSHBindToParent)
3842 win_skip("SHBindToParent missing.\n");
3846 GetCurrentDirectoryW(MAX_PATH, path);
3849 skip("GetCurrentDirectoryW returned an empty string.\n");
3852 lstrcatW(path, filename);
3853 SHGetDesktopFolder(&psf_desktop);
3855 CreateFilesFolders();
3857 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, path, NULL, &pidl, 0);
3858 ok(hr == S_OK || broken(hr == E_FAIL) /* WinME */, "Got 0x%08x\n", hr);
3862 LPCITEMIDLIST pidl_child;
3863 hr = pSHBindToParent(pidl, &IID_IShellFolder, (void**)&psf, &pidl_child);
3864 ok(hr == S_OK, "Got 0x%08x\n", hr);
3867 hr = IShellFolder_GetUIObjectOf(psf, NULL, 1, (LPCITEMIDLIST*)&pidl_child,
3868 &IID_IContextMenu, NULL, (void**)&pcm);
3869 ok(hr == S_OK, "Got 0x%08x\n", hr);
3872 HMENU hmenu = CreatePopupMenu();
3873 INT max_id, max_id_check;
3875 const int id_upper_limit = 32767;
3876 hr = IContextMenu_QueryContextMenu(pcm, hmenu, 0, 0, id_upper_limit, CMF_NORMAL);
3877 ok(SUCCEEDED(hr), "Got 0x%08x\n", hr);
3878 max_id = HRESULT_CODE(hr) - 1; /* returns max_id + 1 */
3879 ok(max_id <= id_upper_limit, "Got %d\n", max_id);
3880 count = GetMenuItemCount(hmenu);
3881 ok(count, "Got %d\n", count);
3884 for(i = 0; i < count; i++)
3888 ZeroMemory(&mii, sizeof(MENUITEMINFOA));
3889 mii.cbSize = sizeof(MENUITEMINFOA);
3890 mii.fMask = MIIM_ID | MIIM_FTYPE;
3893 res = GetMenuItemInfoA(hmenu, i, TRUE, &mii);
3894 ok(res, "Failed (last error: %d).\n", GetLastError());
3896 ok( (mii.wID <= id_upper_limit) || (mii.fType & MFT_SEPARATOR),
3897 "Got non-separator ID out of range: %d (type: %x)\n", mii.wID, mii.fType);
3898 if(!(mii.fType & MFT_SEPARATOR))
3899 max_id_check = (mii.wID>max_id_check)?mii.wID:max_id_check;
3901 ok((max_id_check == max_id) ||
3902 (max_id_check == max_id-1 /* Win 7 */),
3903 "Not equal (or near equal), got %d and %d\n", max_id_check, max_id);
3905 #define is_win2k() (pSHGetFolderPathA && !pSHGetFolderPathAndSubDirA)
3907 if(count && !is_win2k()) /* Test is interactive on w2k, so skip */
3909 CMINVOKECOMMANDINFO cmi;
3910 ZeroMemory(&cmi, sizeof(CMINVOKECOMMANDINFO));
3911 cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
3913 /* Attempt to execute a nonexistent command */
3914 cmi.lpVerb = MAKEINTRESOURCEA(9999);
3915 hr = IContextMenu_InvokeCommand(pcm, &cmi);
3916 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3918 cmi.lpVerb = "foobar_wine_test";
3919 hr = IContextMenu_InvokeCommand(pcm, &cmi);
3920 ok( (hr == E_INVALIDARG) || (hr == E_FAIL /* Win7 */) ||
3921 (hr == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION) /* Vista */),
3922 "Got 0x%08x\n", hr);
3927 IContextMenu_Release(pcm);
3929 IShellFolder_Release(psf);
3931 if(pILFree) pILFree(pidl);
3934 IShellFolder_Release(psf_desktop);
3938 #define verify_pidl(i,p) r_verify_pidl(__LINE__, i, p)
3939 static void r_verify_pidl(unsigned l, LPCITEMIDLIST pidl, const WCHAR *path)
3941 LPCITEMIDLIST child;
3942 IShellFolder *parent;
3946 if(!pSHBindToParent){
3947 win_skip("SHBindToParent is not available, not performing full PIDL verification\n");
3949 ok_(__FILE__,l)(pidl != NULL, "Expected PIDL to be non-NULL\n");
3951 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
3957 ok_(__FILE__,l)(0, "didn't get expected path (%s), instead: NULL\n", wine_dbgstr_w(path));
3961 hr = pSHBindToParent(pidl, &IID_IShellFolder, (LPVOID*)&parent, &child);
3962 ok_(__FILE__,l)(hr == S_OK, "SHBindToParent failed: 0x%08x\n", hr);
3966 hr = IShellFolder_GetDisplayNameOf(parent, child, SHGDN_FORPARSING, &filename);
3967 ok_(__FILE__,l)(hr == S_OK, "GetDisplayNameOf failed: 0x%08x\n", hr);
3969 IShellFolder_Release(parent);
3973 ok_(__FILE__,l)(filename.uType == STRRET_WSTR || filename.uType == STRRET_CSTR,
3974 "Got unexpected string type: %d\n", filename.uType);
3975 if(filename.uType == STRRET_WSTR){
3976 ok_(__FILE__,l)(lstrcmpW(path, U(filename).pOleStr) == 0,
3977 "didn't get expected path (%s), instead: %s\n",
3978 wine_dbgstr_w(path), wine_dbgstr_w(U(filename).pOleStr));
3979 }else if(filename.uType == STRRET_CSTR){
3980 ok_(__FILE__,l)(strcmp_wa(path, U(filename).cStr) == 0,
3981 "didn't get expected path (%s), instead: %s\n",
3982 wine_dbgstr_w(path), U(filename).cStr);
3985 IShellFolder_Release(parent);
3987 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
3990 static void test_SHSimpleIDListFromPath(void)
3992 const WCHAR adirW[] = {'C',':','\\','s','i','d','l','f','p','d','i','r',0};
3993 const CHAR adirA[] = "C:\\sidlfpdir";
3994 BOOL br, is_unicode = !(GetVersion() & 0x80000000);
3996 LPITEMIDLIST pidl = NULL;
3998 if(!pSHSimpleIDListFromPathAW){
3999 win_skip("SHSimpleIDListFromPathAW not available\n");
4003 br = CreateDirectoryA(adirA, NULL);
4004 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
4007 pidl = pSHSimpleIDListFromPathAW(adirW);
4009 pidl = pSHSimpleIDListFromPathAW(adirA);
4010 verify_pidl(pidl, adirW);
4013 br = RemoveDirectoryA(adirA);
4014 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4017 pidl = pSHSimpleIDListFromPathAW(adirW);
4019 pidl = pSHSimpleIDListFromPathAW(adirA);
4020 verify_pidl(pidl, adirW);
4024 /* IFileSystemBindData impl */
4025 static HRESULT WINAPI fsbd_QueryInterface(IFileSystemBindData *fsbd,
4026 REFIID riid, void **ppv)
4028 if(IsEqualIID(riid, &IID_IFileSystemBindData) ||
4029 IsEqualIID(riid, &IID_IUnknown)){
4033 return E_NOINTERFACE;
4036 static ULONG WINAPI fsbd_AddRef(IFileSystemBindData *fsbd)
4041 static ULONG WINAPI fsbd_Release(IFileSystemBindData *fsbd)
4046 static HRESULT WINAPI fsbd_SetFindData(IFileSystemBindData *fsbd,
4047 const WIN32_FIND_DATAW *pfd)
4049 ok(0, "SetFindData called\n");
4053 static HRESULT WINAPI fsbd_GetFindData_nul(IFileSystemBindData *fsbd,
4054 WIN32_FIND_DATAW *pfd)
4056 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
4060 static HRESULT WINAPI fsbd_GetFindData_junk(IFileSystemBindData *fsbd,
4061 WIN32_FIND_DATAW *pfd)
4063 memset(pfd, 0xdeadbeef, sizeof(WIN32_FIND_DATAW));
4067 static HRESULT WINAPI fsbd_GetFindData_invalid(IFileSystemBindData *fsbd,
4068 WIN32_FIND_DATAW *pfd)
4070 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
4071 *pfd->cFileName = 'a';
4072 *pfd->cAlternateFileName = 'a';
4076 static HRESULT WINAPI fsbd_GetFindData_valid(IFileSystemBindData *fsbd,
4077 WIN32_FIND_DATAW *pfd)
4079 static const WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4080 HANDLE handle = FindFirstFileW(adirW, pfd);
4085 static HRESULT WINAPI fsbd_GetFindData_fail(IFileSystemBindData *fsbd,
4086 WIN32_FIND_DATAW *pfd)
4091 static IFileSystemBindDataVtbl fsbdVtbl = {
4092 fsbd_QueryInterface,
4099 static IFileSystemBindData fsbd = { &fsbdVtbl };
4101 static void test_ParseDisplayNamePBC(void)
4103 WCHAR wFileSystemBindData[] =
4104 {'F','i','l','e',' ','S','y','s','t','e','m',' ','B','i','n','d',' ','D','a','t','a',0};
4105 WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4106 WCHAR afileW[] = {'C',':','\\','f','s','b','d','d','i','r','\\','f','i','l','e','.','t','x','t',0};
4107 WCHAR afile2W[] = {'C',':','\\','f','s','b','d','d','i','r','\\','s','\\','f','i','l','e','.','t','x','t',0};
4108 const HRESULT exp_err = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
4115 /* Check if we support WCHAR functions */
4116 SetLastError(0xdeadbeef);
4117 lstrcmpiW(adirW, adirW);
4118 if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED){
4119 win_skip("Most W-calls are not implemented\n");
4123 hres = SHGetDesktopFolder(&psf);
4124 ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
4126 win_skip("Failed to get IShellFolder, can't run tests\n");
4130 /* fails on unknown dir with no IBindCtx */
4131 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, adirW, NULL, &pidl, NULL);
4132 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4133 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4134 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, afileW, 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, afile2W, NULL, &pidl, NULL);
4138 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4139 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4141 /* fails on unknown dir with IBindCtx with no IFileSystemBindData */
4142 hres = CreateBindCtx(0, &pbc);
4143 ok(hres == S_OK, "CreateBindCtx failed: 0x%08x\n", hres);
4145 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4146 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4147 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4148 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, 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, afile2W, NULL, &pidl, NULL);
4152 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4153 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4155 /* unknown dir with IBindCtx with IFileSystemBindData */
4156 hres = IBindCtx_RegisterObjectParam(pbc, wFileSystemBindData, (IUnknown*)&fsbd);
4157 ok(hres == S_OK, "RegisterObjectParam failed: 0x%08x\n", hres);
4159 /* return E_FAIL from GetFindData */
4160 pidl = (ITEMIDLIST*)0xdeadbeef;
4161 fsbdVtbl.GetFindData = fsbd_GetFindData_fail;
4162 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4163 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4164 "ParseDisplayName failed: 0x%08x\n", hres);
4165 if(SUCCEEDED(hres)){
4166 verify_pidl(pidl, adirW);
4170 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4171 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4172 "ParseDisplayName failed: 0x%08x\n", hres);
4173 if(SUCCEEDED(hres)){
4174 verify_pidl(pidl, afileW);
4178 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4179 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4180 "ParseDisplayName failed: 0x%08x\n", hres);
4181 if(SUCCEEDED(hres)){
4182 verify_pidl(pidl, afile2W);
4186 /* set FIND_DATA struct to NULLs */
4187 pidl = (ITEMIDLIST*)0xdeadbeef;
4188 fsbdVtbl.GetFindData = fsbd_GetFindData_nul;
4189 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4190 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4191 "ParseDisplayName failed: 0x%08x\n", hres);
4192 if(SUCCEEDED(hres)){
4193 verify_pidl(pidl, adirW);
4197 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4198 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4199 "ParseDisplayName failed: 0x%08x\n", hres);
4200 if(SUCCEEDED(hres)){
4201 verify_pidl(pidl, afileW);
4205 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4206 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4207 "ParseDisplayName failed: 0x%08x\n", hres);
4208 if(SUCCEEDED(hres)){
4209 verify_pidl(pidl, afile2W);
4213 /* set FIND_DATA struct to junk */
4214 pidl = (ITEMIDLIST*)0xdeadbeef;
4215 fsbdVtbl.GetFindData = fsbd_GetFindData_junk;
4216 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4217 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4218 "ParseDisplayName failed: 0x%08x\n", hres);
4219 if(SUCCEEDED(hres)){
4220 verify_pidl(pidl, adirW);
4224 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4225 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4226 "ParseDisplayName failed: 0x%08x\n", hres);
4227 if(SUCCEEDED(hres)){
4228 verify_pidl(pidl, afileW);
4232 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4233 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4234 "ParseDisplayName failed: 0x%08x\n", hres);
4235 if(SUCCEEDED(hres)){
4236 verify_pidl(pidl, afile2W);
4240 /* set FIND_DATA struct to invalid data */
4241 pidl = (ITEMIDLIST*)0xdeadbeef;
4242 fsbdVtbl.GetFindData = fsbd_GetFindData_invalid;
4243 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4244 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4245 "ParseDisplayName failed: 0x%08x\n", hres);
4246 if(SUCCEEDED(hres)){
4247 verify_pidl(pidl, adirW);
4251 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4252 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4253 "ParseDisplayName failed: 0x%08x\n", hres);
4254 if(SUCCEEDED(hres)){
4255 verify_pidl(pidl, afileW);
4259 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4260 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4261 "ParseDisplayName failed: 0x%08x\n", hres);
4262 if(SUCCEEDED(hres)){
4263 verify_pidl(pidl, afile2W);
4267 /* set FIND_DATA struct to valid data */
4268 pidl = (ITEMIDLIST*)0xdeadbeef;
4269 fsbdVtbl.GetFindData = fsbd_GetFindData_valid;
4270 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4271 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4272 "ParseDisplayName failed: 0x%08x\n", hres);
4273 if(SUCCEEDED(hres)){
4274 verify_pidl(pidl, adirW);
4278 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4279 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4280 "ParseDisplayName failed: 0x%08x\n", hres);
4281 if(SUCCEEDED(hres)){
4282 verify_pidl(pidl, afileW);
4286 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4287 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4288 "ParseDisplayName failed: 0x%08x\n", hres);
4289 if(SUCCEEDED(hres)){
4290 verify_pidl(pidl, afile2W);
4294 IBindCtx_Release(pbc);
4295 IShellFolder_Release(psf);
4298 static const CHAR testwindow_class[] = "testwindow";
4299 #define WM_USER_NOTIFY (WM_APP+1)
4301 struct ChNotifyTest {
4303 const UINT notify_count;
4304 UINT missing_events;
4306 const char path_1[256];
4307 const char path_2[256];
4308 } chnotify_tests[] = {
4309 {"MKDIR", 1, 0, SHCNE_MKDIR, "C:\\shell32_cn_test\\test", ""},
4310 {"CREATE", 1, 0, SHCNE_CREATE, "C:\\shell32_cn_test\\test\\file.txt", ""},
4311 {"RMDIR", 1, 0, SHCNE_RMDIR, "C:\\shell32_cn_test\\test", ""},
4314 struct ChNotifyTest *exp_data;
4316 static LRESULT CALLBACK testwindow_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
4318 UINT signal = (UINT)lparam;
4321 case WM_USER_NOTIFY:
4322 if(exp_data->missing_events > 0){
4323 WCHAR *path1, *path2;
4324 LPCITEMIDLIST *pidls = (LPCITEMIDLIST*)wparam;
4326 ok(exp_data->signal == signal,
4327 "%s: expected notification type %x, got: %x\n",
4328 exp_data->id, exp_data->signal, signal);
4330 trace("verifying pidls for: %s\n", exp_data->id);
4331 path1 = make_wstr(exp_data->path_1);
4332 path2 = make_wstr(exp_data->path_2);
4333 verify_pidl(pidls[0], path1);
4334 verify_pidl(pidls[1], path2);
4335 HeapFree(GetProcessHeap(), 0, path1);
4336 HeapFree(GetProcessHeap(), 0, path2);
4338 exp_data->missing_events--;
4340 ok(0, "Didn't expect a WM_USER_NOTIFY message (event: %x)\n", signal);
4343 return DefWindowProc(hwnd, msg, wparam, lparam);
4346 static void register_testwindow_class(void)
4351 ZeroMemory(&cls, sizeof(cls));
4352 cls.cbSize = sizeof(cls);
4354 cls.lpfnWndProc = testwindow_wndproc;
4355 cls.hInstance = GetModuleHandleA(NULL);
4356 cls.lpszClassName = testwindow_class;
4359 ret = RegisterClassExA(&cls);
4360 ok(ret != 0, "RegisterClassExA failed: %d\n", GetLastError());
4363 /* SHCNF_FLUSH doesn't seem to work as advertised for SHCNF_PATHA, so we
4364 * have to poll repeatedly for the message to appear */
4365 static void do_events(void)
4368 while (exp_data->missing_events && (c++ < 10)){
4370 while(PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)){
4371 TranslateMessage(&msg);
4372 DispatchMessageA(&msg);
4374 if(exp_data->missing_events)
4377 trace("%s: took %d tries\n", exp_data->id, c);
4380 static void test_SHChangeNotify(void)
4385 BOOL br, has_unicode;
4386 SHChangeNotifyEntry entries[1];
4387 const CHAR root_dirA[] = "C:\\shell32_cn_test";
4388 const WCHAR root_dirW[] = {'C',':','\\','s','h','e','l','l','3','2','_','c','n','_','t','e','s','t',0};
4390 CreateDirectoryW(NULL, NULL);
4391 has_unicode = !(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED);
4393 register_testwindow_class();
4395 wnd = CreateWindowExA(0, testwindow_class, testwindow_class, 0,
4396 CW_USEDEFAULT, CW_USEDEFAULT, 130, 105,
4397 NULL, NULL, GetModuleHandleA(NULL), 0);
4398 ok(wnd != NULL, "Failed to make a window\n");
4400 br = CreateDirectoryA(root_dirA, NULL);
4401 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
4403 entries[0].pidl = NULL;
4405 hr = SHILCreateFromPath(root_dirW, (LPITEMIDLIST*)&entries[0].pidl, 0);
4407 hr = SHILCreateFromPath((LPCVOID)root_dirA, (LPITEMIDLIST*)&entries[0].pidl, 0);
4408 ok(hr == S_OK, "SHILCreateFromPath failed: 0x%08x\n", hr);
4409 entries[0].fRecursive = TRUE;
4411 notifyID = SHChangeNotifyRegister(wnd, SHCNRF_ShellLevel,
4412 SHCNE_ALLEVENTS, WM_USER_NOTIFY, 1, entries);
4413 ok(notifyID != 0, "Failed to register a window for change notifications\n");
4415 for(i = 0; i < sizeof(chnotify_tests) / sizeof(*chnotify_tests); ++i){
4416 exp_data = chnotify_tests + i;
4418 exp_data->missing_events = exp_data->notify_count;
4419 SHChangeNotify(exp_data->signal, SHCNF_PATHA | SHCNF_FLUSH,
4420 strlen(exp_data->path_1) > 0 ? exp_data->path_1 : NULL,
4421 strlen(exp_data->path_2) > 0 ? exp_data->path_2 : NULL);
4423 ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
4426 WCHAR *path1, *path2;
4428 path1 = make_wstr(exp_data->path_1);
4429 path2 = make_wstr(exp_data->path_2);
4431 exp_data->missing_events = exp_data->notify_count;
4432 SHChangeNotify(exp_data->signal, SHCNF_PATHW | SHCNF_FLUSH, path1, path2);
4434 ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
4438 SHChangeNotifyDeregister(notifyID);
4441 br = RemoveDirectoryA(root_dirA);
4442 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4445 START_TEST(shlfolder)
4447 init_function_pointers();
4448 /* if OleInitialize doesn't get called, ParseDisplayName returns
4449 CO_E_NOTINITIALIZED for malformed directory names on win2k. */
4450 OleInitialize(NULL);
4452 test_ParseDisplayName();
4453 test_SHParseDisplayName();
4454 test_BindToObject();
4455 test_EnumObjects_and_CompareIDs();
4456 test_GetDisplayName();
4457 test_GetAttributesOf();
4458 test_SHGetPathFromIDList();
4459 test_CallForAttributes();
4460 test_FolderShortcut();
4461 test_ITEMIDLIST_format();
4462 test_SHGetFolderPathA();
4463 test_SHGetFolderPathAndSubDirA();
4464 test_LocalizedNames();
4465 test_SHCreateShellItem();
4466 test_SHCreateShellItemArray();
4467 test_desktop_IPersist();
4469 test_SHSimpleIDListFromPath();
4470 test_ParseDisplayNamePBC();
4471 test_SHGetNameFromIDList();
4472 test_SHGetItemFromDataObject();
4473 test_SHGetIDListFromObject();
4474 test_SHGetItemFromObject();
4475 test_ShellItemCompare();
4476 test_SHChangeNotify();
4477 test_ShellItemBindToHandler();
4478 test_ShellItemGetAttributes();