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